diff --git a/core/modules/layout_builder/layout_builder.services.yml b/core/modules/layout_builder/layout_builder.services.yml
index 56b4bf88bd..7edd0836f4 100644
--- a/core/modules/layout_builder/layout_builder.services.yml
+++ b/core/modules/layout_builder/layout_builder.services.yml
@@ -46,3 +46,14 @@ services:
   inline_block.usage:
     class: Drupal\layout_builder\InlineBlockUsage
     arguments: ['@database']
+  layout_builder.normalizer.section_data:
+    class: Drupal\layout_builder\Normalizer\SectionDataNormalizer
+    tags:
+      # Priority must be higher than serializer.normalizer.typed_data.
+      - { name: normalizer, priority: 1 }
+  layout_builder.normalizer.layout_section_item:
+    class: Drupal\layout_builder\Normalizer\LayoutSectionItemNormalizer
+    public: false
+    tags:
+      # Priority must be higher than serializer.normalizer.entity_reference_field_item.
+      - { name: normalizer, priority: 9 }
diff --git a/core/modules/layout_builder/src/Normalizer/LayoutSectionItemNormalizer.php b/core/modules/layout_builder/src/Normalizer/LayoutSectionItemNormalizer.php
new file mode 100644
index 0000000000..90e18691b6
--- /dev/null
+++ b/core/modules/layout_builder/src/Normalizer/LayoutSectionItemNormalizer.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\layout_builder\Normalizer;
+
+use Drupal\layout_builder\Plugin\DataType\SectionData;
+use Drupal\layout_builder\Plugin\Field\FieldType\LayoutSectionItem;
+use Drupal\serialization\Normalizer\FieldItemNormalizer;
+
+/**
+ * Normalizes section lists.
+ *
+ * @todo Remove in https://www.drupal.org/node/issues/2957385
+ *
+ * @internal
+ */
+class LayoutSectionItemNormalizer extends FieldItemNormalizer {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $supportedInterfaceOrClass = LayoutSectionItem::class;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function denormalize($data, $class, $format = NULL, array $context = []) {
+    /** @var \Drupal\layout_builder\Plugin\DataType\SectionData $section_data */
+    $section_data = $this->serializer->denormalize($data['section'], SectionData::class, $format, $context);;
+    return parent::denormalize($section_data->getValue(), $class, $format, $context);
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Normalizer/SectionDataNormalizer.php b/core/modules/layout_builder/src/Normalizer/SectionDataNormalizer.php
new file mode 100644
index 0000000000..25944a2ae6
--- /dev/null
+++ b/core/modules/layout_builder/src/Normalizer/SectionDataNormalizer.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Drupal\layout_builder\Normalizer;
+
+use Drupal\layout_builder\Plugin\DataType\SectionData;
+use Drupal\layout_builder\Section;
+use Drupal\serialization\Normalizer\TypedDataNormalizer;
+use Symfony\Component\Serializer\Exception\InvalidArgumentException;
+use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
+
+/**
+ * Normalizes section data.
+ */
+class SectionDataNormalizer extends TypedDataNormalizer implements DenormalizerInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $supportedInterfaceOrClass = SectionData::class;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function normalize($object, $format = NULL, array $context = []) {
+    return $object->getValue()->toArray();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function denormalize($data, $class, $format = NULL, array $context = []) {
+    if (!isset($context['target_instance'])) {
+      throw new InvalidArgumentException('$context[\'target_instance\'] must be set to denormalize with the SectionDataNormalizer');
+    }
+
+    /** @var \Drupal\Core\Field\FieldItemInterface $field_item */
+    $target_instance = $context['target_instance'];
+
+    $object = SectionData::createInstance($target_instance->getDataDefinition());
+    $section = Section::fromArray($data);
+    $object->setValue($section);
+    return $object;
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Plugin/DataType/SectionData.php b/core/modules/layout_builder/src/Plugin/DataType/SectionData.php
index 353c53fe7c..79f8f161d7 100644
--- a/core/modules/layout_builder/src/Plugin/DataType/SectionData.php
+++ b/core/modules/layout_builder/src/Plugin/DataType/SectionData.php
@@ -27,6 +27,9 @@ class SectionData extends TypedData {
    * {@inheritdoc}
    */
   public function setValue($value, $notify = TRUE) {
+    if ($value && is_array($value)) {
+      $value = Section::fromArray($value);
+    }
     if ($value && !$value instanceof Section) {
       throw new \InvalidArgumentException(sprintf('Value assigned to "%s" is not a valid section', $this->getName()));
     }
diff --git a/core/modules/layout_builder/tests/src/Unit/SectionDataNormalizerTest.php b/core/modules/layout_builder/tests/src/Unit/SectionDataNormalizerTest.php
new file mode 100644
index 0000000000..17e07e2d3e
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Unit/SectionDataNormalizerTest.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Unit;
+
+use Drupal\Core\Field\FieldItemInterface;
+use Drupal\Core\TypedData\DataDefinitionInterface;
+use Symfony\Component\Serializer\Exception\InvalidArgumentException;
+use Drupal\layout_builder\Normalizer\SectionDataNormalizer;
+use Drupal\layout_builder\Plugin\DataType\SectionData;
+use Drupal\layout_builder\Section;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\layout_builder\Normalizer\SectionDataNormalizer
+ * @group layout_builder
+ */
+class SectionDataNormalizerTest extends UnitTestCase {
+
+  /**
+   * The normalizer.
+   *
+   * @var \Drupal\layout_builder\Normalizer\SectionDataNormalizer
+   */
+  protected $normalizer;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->normalizer = new SectionDataNormalizer();
+  }
+
+  /**
+   * @covers ::supportsNormalization
+   */
+  public function testSupportsNormalization() {
+    $section_data = $this->prophesize(SectionData::class);
+    $this->assertTrue($this->normalizer->supportsNormalization($section_data->reveal()));
+  }
+
+  /**
+   * @covers ::supportsDenormalization
+   */
+  public function testSupportsDenormalization() {
+    $this->assertTrue($this->normalizer->supportsDenormalization([], SectionData::class));
+  }
+
+  /**
+   * Tests the normalize function.
+   *
+   * @covers ::normalize
+   */
+  public function testNormalize() {
+    $data = ['foo'];
+    $section_data = $this->prophesize(SectionData::class);
+    $section = $this->prophesize(Section::class);
+    $section->toArray()
+      ->willReturn($data);
+    $section_data->getValue()
+      ->willReturn($section);
+    $this->assertArrayEquals($data, $this->normalizer->normalize($section_data->reveal()));
+  }
+
+  /**
+   * Tests the denormalize function.
+   *
+   * @covers ::denormalize
+   */
+  public function testDenormalize() {
+    $data = ['foo'];
+    $target_instance = $this->prophesize(FieldItemInterface::class);
+    $target_instance->getDataDefinition()
+      ->willReturn($this->prophesize(DataDefinitionInterface::class));
+    $context = [
+      'target_instance' => [
+        $target_instance,
+      ],
+    ];
+    $this->setExpectedException(InvalidArgumentException::class);
+    $this->normalizer->denormalize($data, SectionData::class);
+    $section_data = $this->normalizer->denormalize($data, SectionData::class, $context);
+    $this->assertArrayEquals($data, $section_data->getValue()->toArray());
+  }
+
+}