diff --git a/panels_ipe/js/panels_ipe.js b/panels_ipe/js/panels_ipe.js
index 26bcc01..3000fdd 100644
--- a/panels_ipe/js/panels_ipe.js
+++ b/panels_ipe/js/panels_ipe.js
@@ -68,7 +68,9 @@
   Drupal.panels_ipe.init = function (settings) {
     // Set up our initial tabs.
     var tab_collection = new Drupal.panels_ipe.TabCollection();
-    tab_collection.add({title: 'Change Layout', id: 'change_layout'});
+    if (settings.panels_ipe.layout.changeable) {
+      tab_collection.add({title: 'Change Layout', id: 'change_layout'});
+    }
     tab_collection.add({title: 'Manage Content', id: 'manage_content'});
 
     // The edit/save/cancel tabs are special, and are tracked by our app.
@@ -89,10 +91,11 @@
     });
 
     // Set up our initial tab views.
-    var tab_views = {
-      change_layout: new Drupal.panels_ipe.LayoutPicker(),
-      manage_content: new Drupal.panels_ipe.BlockPicker()
-    };
+    var tab_views = {};
+    if (settings.panels_ipe.layout.changeable) {
+      tab_views.change_layout = new Drupal.panels_ipe.LayoutPicker();
+    }
+    tab_views.manage_content = new Drupal.panels_ipe.BlockPicker();
 
     // Create an AppView instance.
     var app_view = new Drupal.panels_ipe.AppView({
diff --git a/panels_ipe/panels_ipe.routing.yml b/panels_ipe/panels_ipe.routing.yml
index 6fc1383..f965c61 100644
--- a/panels_ipe/panels_ipe.routing.yml
+++ b/panels_ipe/panels_ipe.routing.yml
@@ -45,7 +45,7 @@ panels_ipe.layout.form:
   defaults:
     _controller: '\Drupal\panels_ipe\Controller\PanelsIPEPageController::getLayoutForm'
   requirements:
-    _panels_storage_access: read
+    _panels_storage_access: 'change layout'
     _permission: 'access panels in-place editing'
 
 panels_ipe.layout.update:
diff --git a/panels_ipe/src/Plugin/DisplayBuilder/InPlaceEditorDisplayBuilder.php b/panels_ipe/src/Plugin/DisplayBuilder/InPlaceEditorDisplayBuilder.php
index 87fda57..6f92bbe 100644
--- a/panels_ipe/src/Plugin/DisplayBuilder/InPlaceEditorDisplayBuilder.php
+++ b/panels_ipe/src/Plugin/DisplayBuilder/InPlaceEditorDisplayBuilder.php
@@ -123,18 +123,22 @@ class InPlaceEditorDisplayBuilder extends StandardDisplayBuilder {
       }
     }
 
+    $storage_type = $panels_display->getStorageType();
+    $storage_id = $panels_display->getStorageId();
+
     // Add the layout information.
     $layout_definition = $layout->getPluginDefinition();
     $settings['layout'] = [
       'id' => $layout->getPluginId(),
       'label' => $layout_definition['label'],
       'original' => true,
+      'changeable' => $this->panelsStorage->access($storage_type, $storage_id, 'change layout', $this->account)->isAllowed(),
     ];
 
     // Add the display variant's config.
     $settings['panels_display'] = [
-      'storage_type' => $panels_display->getStorageType(),
-      'storage_id' => $panels_display->getStorageId(),
+      'storage_type' => $storage_type,
+      'storage_id' => $storage_id,
       'id' => $panels_display->id(),
     ];
 
diff --git a/src/Storage/PanelsStorageInterface.php b/src/Storage/PanelsStorageInterface.php
index e1b8442..8733b3c 100644
--- a/src/Storage/PanelsStorageInterface.php
+++ b/src/Storage/PanelsStorageInterface.php
@@ -44,7 +44,9 @@ interface PanelsStorageInterface {
    * @param string $id
    *   The id for the Panels display within this storage plugin.
    * @param string $op
-   *   The operation to perform (ie. create, read, update, delete).
+   *   The operation to perform (create, read, update, delete, change layout).
+   *   If the operation is 'change layout', implementing classes should
+   *   implicitly check the 'update' permission as well.
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The user to check access for.
    *
