diff --git a/core/modules/link/src/Plugin/migrate/process/d6/CckLink.php b/core/modules/link/src/Plugin/migrate/process/d6/CckLink.php
index 47c2f8b..1df0550 100644
--- a/core/modules/link/src/Plugin/migrate/process/d6/CckLink.php
+++ b/core/modules/link/src/Plugin/migrate/process/d6/CckLink.php
@@ -37,6 +37,35 @@ public static function create(ContainerInterface $container, array $configuratio
   }
 
   /**
+   * Turn a Drupal 6 or 7 URI into a Drupal 8-compatible format.
+   *
+   * @param string $uri
+   *   The 'url' value from Drupal 6 or 7.
+   *
+   * @return string
+   *   The Drupal 8-compatible URI.
+   *
+   * @see \Drupal\link\Plugin\Field\FieldWidget\LinkWidget::getUserEnteredStringAsUri()
+   */
+  protected static function canonicalizeUri($uri) {
+    // If we already have a scheme, we're fine.
+    if (empty($uri) || !is_null(parse_url($uri, PHP_URL_SCHEME))) {
+      return $uri;
+    }
+
+    // Maybe it's a <front> URL?
+    if (strpos($uri, '<front>') === 0) {
+      $uri = '/' . substr($uri, strlen('<front>'));
+    }
+
+    // Make sure we start with a slash, this wasn't a requirement in D6/7.
+    $uri = preg_replace('#^/?#', '/', $uri);
+
+    // Add the internal: scheme.
+    return 'internal:' . $uri;
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
@@ -51,7 +80,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
     }
 
     // Massage the values into the correct form for the link.
-    $route['uri'] = $value['url'];
+    $route['uri'] = self::canonicalizeUri($value['url']);
     $route['options']['attributes'] = $attributes;
     $route['title'] = $value['title'];
     return $route;
diff --git a/core/modules/migrate_drupal/tests/fixtures/drupal6.php b/core/modules/migrate_drupal/tests/fixtures/drupal6.php
index 1ca67a5..b5efabc 100644
--- a/core/modules/migrate_drupal/tests/fixtures/drupal6.php
+++ b/core/modules/migrate_drupal/tests/fixtures/drupal6.php
@@ -3420,9 +3420,9 @@
   'field_test_three_value' => '101.00',
   'field_test_identical1_value' => NULL,
   'field_test_identical2_value' => NULL,
-  'field_test_link_url' => 'http://www.example.com/buy-one-upon-a-time',
+  'field_test_link_url' => 'node/10',
   'field_test_link_title' => 'Buy it now',
-  'field_test_link_attributes' => 'a:1:{s:6:"target";s:6:"_blank";}',
+  'field_test_link_attributes' => 's:32:"a:1:{s:6:"target";s:6:"_blank";}";',
   'field_test_date_value' => NULL,
   'field_test_datestamp_value' => NULL,
   'field_test_datetime_value' => NULL,
@@ -3440,7 +3440,7 @@
   'field_test_imagefield_fid' => NULL,
   'field_test_imagefield_list' => NULL,
   'field_test_imagefield_data' => NULL,
-  'field_test_text_single_checkbox2_value' => NULL,
+  'field_test_text_single_checkbox2_value' => 'Off',
 ))
 ->execute();
 
diff --git a/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php b/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php
index 29bc9dc..0a51e35 100644
--- a/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php
+++ b/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php
@@ -79,6 +79,12 @@ public function testNode() {
     $this->assertIdentical('Drupal Groups', $node->field_test_link->title);
     $this->assertIdentical([], $node->field_test_link->options['attributes']);
 
+    // Test that a link field with an internal link is migrated.
+    $node = Node::load(9);
+    $this->assertEquals('internal:/node/10', $node->field_test_link->uri);
+    $this->assertEquals('Buy it now', $node->field_test_link->title);
+    $this->assertEquals(['attributes' => ['target' => '_blank']], $node->field_test_link->options);
+
     // Rerun migration with invalid link attributes and a different URL and
     // title. If only the attributes are changed the error does not occur.
     Database::getConnection('default', 'migrate')
