diff --git a/core/modules/block_place/block_place.info.yml b/core/modules/block_place/block_place.info.yml
new file mode 100644
index 0000000..8ae7226
--- /dev/null
+++ b/core/modules/block_place/block_place.info.yml
@@ -0,0 +1,8 @@
+name: Place Blocks
+type: module
+description: 'Allow administrators to place blocks from any Drupal page'
+package: Core (Experimental)
+version: VERSION
+core: 8.x
+dependencies:
+  - block
diff --git a/core/modules/block_place/block_place.module b/core/modules/block_place/block_place.module
new file mode 100644
index 0000000..0667769
--- /dev/null
+++ b/core/modules/block_place/block_place.module
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Implements hook_toolbar().
+ */
+function block_place_toolbar() {
+  // Link to the current page with a query parameter.
+  $url = \Drupal\Core\Url::fromRoute('<current>');
+  $request = \Drupal::request();
+  $query = $request->query->all();
+  if (isset($query['block-place'])) {
+    $title = t('Cancel place block');
+    $description = t('Cancel placing a block on the page.');
+    unset($query['block-place']);
+  }
+  else {
+    $title = t('Place block');
+    $description = t('Place a block on the page.');
+    $query['block-place'] = '1';
+  }
+  $url->setOption('query', $query);
+  // The 'Home' tab is a simple link, with no corresponding tray.
+  $items['block_place'] = array(
+    '#cache' => [
+      'contexts' => ['user.permissions', 'url.query_args'],
+    ],
+    '#access' => \Drupal::currentUser()->hasPermission('administer blocks'),
+    '#type' => 'toolbar_item',
+    'tab' => array(
+      '#type' => 'link',
+      '#title' => $title,
+      '#url' => $url,
+      '#attributes' => array(
+        'title' => $description,
+        'class' => array('toolbar-icon', 'toolbar-icon-system-admin-structure'),
+      ),
+    ),
+    '#wrapper_attributes' => array(
+      'class' => array('block-place-toolbar-tab'),
+    ),
+    '#attached' => array(
+      'library' => array(
+        'toolbar/toolbar.escapeAdmin',
+      ),
+    ),
+    '#weight' => 100,
+  );
+  return $items;
+}
\ No newline at end of file
diff --git a/core/modules/block_place/block_place.services.yml b/core/modules/block_place/block_place.services.yml
new file mode 100644
index 0000000..e442aca
--- /dev/null
+++ b/core/modules/block_place/block_place.services.yml
@@ -0,0 +1,7 @@
+services:
+  block_place.page_display_variant_subscriber.block:
+    class: Drupal\block_place\EventSubscriber\BlockPlaceEventSubscriber
+    arguments: ['@request_stack', '@current_user']
+    tags:
+      - { name: event_subscriber }
+
diff --git a/core/modules/block_place/src/EventSubscriber/BlockPlaceEventSubscriber.php b/core/modules/block_place/src/EventSubscriber/BlockPlaceEventSubscriber.php
new file mode 100644
index 0000000..9afd141
--- /dev/null
+++ b/core/modules/block_place/src/EventSubscriber/BlockPlaceEventSubscriber.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Drupal\block_place\EventSubscriber;
+
+use Drupal\Core\Render\PageDisplayVariantSelectionEvent;
+use Drupal\Core\Render\RenderEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpFoundation\RequestStack;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * @see \Drupal\block_place\Plugin\DisplayVariant\PlaceBlockPageVariant
+ */
+class BlockPlaceEventSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The request stack.
+   *
+   * @var \Symfony\Component\HttpFoundation\RequestStack
+   */
+  protected $requestStack;
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $account;
+
+  /**
+   * Constructs a \Drupal\block_place\EventSubscriber\BlockPlaceEventSubscriber object.
+   *
+   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
+   *   The request stack used to retrieve the current request.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The current user.
+   */
+  public function __construct(RequestStack $request_stack, AccountInterface $account) {
+    $this->requestStack = $request_stack;
+    $this->account = $account;
+  }
+
+  /**
+   * Selects the block place override of the block page display variant.
+   *
+   * @param \Drupal\Core\Render\PageDisplayVariantSelectionEvent $event
+   *   The event to process.
+   */
+  public function onBlockPageDisplayVariantSelected(PageDisplayVariantSelectionEvent $event) {
+    if ($event->getPluginId() === 'block_page') {
+      if ($this->requestStack->getCurrentRequest()->query->get('block-place')) {
+        if ($this->account->hasPermission('administer blocks')) {
+          $event->setPluginId('block_place_page');
+        }
+      }
+      $event->addCacheContexts(['user.permissions', 'url.query_args']);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  static function getSubscribedEvents() {
+    // Set a very low priority, so that it runs last.
+    $events[RenderEvents::SELECT_PAGE_DISPLAY_VARIANT][] = ['onBlockPageDisplayVariantSelected', -1000];
+    return $events;
+  }
+
+}
diff --git a/core/modules/block_place/src/Plugin/DisplayVariant/PlaceBlockPageVariant.php b/core/modules/block_place/src/Plugin/DisplayVariant/PlaceBlockPageVariant.php
new file mode 100644
index 0000000..4161b1b
--- /dev/null
+++ b/core/modules/block_place/src/Plugin/DisplayVariant/PlaceBlockPageVariant.php
@@ -0,0 +1,108 @@
+<?php
+
+namespace Drupal\block_place\Plugin\DisplayVariant;
+
+use Drupal\block\BlockRepositoryInterface;
+use Drupal\block\Plugin\DisplayVariant\BlockPageVariant;
+use Drupal\Component\Serialization\Json;
+use Drupal\Core\Block\MainContentBlockPluginInterface;
+use Drupal\Core\Block\TitleBlockPluginInterface;
+use Drupal\Core\Block\MessagesBlockPluginInterface;
+use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Display\PageVariantInterface;
+use Drupal\Core\Entity\EntityViewBuilderInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Display\VariantBase;
+use Drupal\Core\Render\Element;
+use Drupal\Core\Theme\ThemeManagerInterface;
+use Drupal\Core\Url;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a page display variant that decorates the main content with blocks.
+ *
+ * @see \Drupal\Core\Block\MainContentBlockPluginInterface
+ * @see \Drupal\Core\Block\MessagesBlockPluginInterface
+ *
+ * @PageDisplayVariant(
+ *   id = "block_place_page",
+ *   admin_label = @Translation("Page with blocks and place block buttons")
+ * )
+ */
+class PlaceBlockPageVariant extends BlockPageVariant {
+
+  /**
+   * The theme manager.
+   *
+   * @var \Drupal\Core\Theme\ThemeManagerInterface
+   */
+  protected $themeManager;
+
+  /**
+   * Constructs a new BlockPageVariant.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin ID for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
+   *   The theme manager.
+   * @param \Drupal\block\BlockRepositoryInterface $block_repository
+   *   The block repository.
+   * @param \Drupal\Core\Entity\EntityViewBuilderInterface $block_view_builder
+   *   The block view builder.
+   * @param string[] $block_list_cache_tags
+   *   The Block entity type list cache tags.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, ThemeManagerInterface $theme_manager, BlockRepositoryInterface $block_repository, EntityViewBuilderInterface $block_view_builder, array $block_list_cache_tags) {
+    $this->themeManager = $theme_manager;
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $block_repository, $block_view_builder, $block_list_cache_tags);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('theme.manager'),
+      $container->get('block.repository'),
+      $container->get('entity.manager')->getViewBuilder('block'),
+      $container->get('entity.manager')->getDefinition('block')->getListCacheTags()
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    $build = parent::build();
+    $active_theme = $this->themeManager->getActiveTheme();
+    // Build an array of the region names in the right order.
+    $empty = array_fill_keys($active_theme->getRegions(), array());
+    $build += $empty;
+    foreach (Element::children($build) as $region) {
+      $links['place_block_add_link'] = [
+        'title' => $this->t('Place block'),
+        'url' => Url::fromRoute('block.admin_library', ['theme' => $active_theme->getName()]),
+        'query' => ['region' => $region],
+        'attributes' => [
+          'class' => ['use-ajax'],
+          'data-dialog-type' => 'modal',
+          'data-dialog-options' => Json::encode([
+            'width' => 700,
+          ]),
+        ],
+      ];
+      $build[$region]['block_place_operations'] = [
+        '#type' => 'operations',
+        '#links' => $links,
+      ];
+    }
+    return $build;
+  }
+}
\ No newline at end of file
