diff --git a/config/install/page_manager.page.moderation_dashboard.yml b/config/install/page_manager.page.moderation_dashboard.yml
index 9432335..dea8a81 100644
--- a/config/install/page_manager.page.moderation_dashboard.yml
+++ b/config/install/page_manager.page.moderation_dashboard.yml
@@ -4,11 +4,27 @@ dependencies:
   enforced:
     module:
       - moderation_dashboard
+  module:
+    - moderation_dashboard
 id: moderation_dashboard
 label: 'Moderation Dashboard'
 description: ''
 use_admin_theme: false
 path: '/user/{user}/moderation/dashboard'
 access_logic: and
-access_conditions: {  }
-parameters: {  }
+access_conditions:
+  -
+    id: has_moderated_content_type
+    negate: false
+    context_mapping: {  }
+  -
+    id: moderation_dashboard_access
+    negate: false
+    context_mapping:
+      dashboard_user: user
+      current_user: current_user
+parameters:
+  user:
+    machine_name: user
+    type: 'entity:user'
+    label: User
diff --git a/config/schema/moderation_dashboard.schema.yml b/config/schema/moderation_dashboard.schema.yml
new file mode 100644
index 0000000..1d750be
--- /dev/null
+++ b/config/schema/moderation_dashboard.schema.yml
@@ -0,0 +1,5 @@
+condition.plugin.moderation_dashboard_access:
+  type: condition.plugin
+
+condition.plugin.has_moderated_content_type:
+  type: condition.plugin
diff --git a/moderation_dashboard.module b/moderation_dashboard.module
index abb5699..005167a 100644
--- a/moderation_dashboard.module
+++ b/moderation_dashboard.module
@@ -5,7 +5,6 @@
  * Contains hooks for the moderation_dashboard module.
  */
 
-use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\ContentEntityTypeInterface;
 use Drupal\Core\Url;
@@ -95,24 +94,3 @@ function moderation_dashboard_preprocess_block(&$variables) {
     $variables['attributes']['class'][] = 'moderation-dashboard-block';
   }
 }
-
-/**
- * Custom access callback for our page manager page.
- *
- * If no Content Type has moderation enabled, users cannot the dashboard.
- */
-function _moderation_dashboard_page_access() {
-  /** @var \Drupal\content_moderation\ModerationInformation $moderation_info */
-  $moderation_info = \Drupal::service('content_moderation.moderation_information');
-  /** @var \Drupal\Core\Entity\EntityTypeBundleInfo $bundle_info */
-  $bundle_info = \Drupal::service('entity_type.bundle.info');
-  $entity_type = \Drupal::entityTypeManager()->getDefinition('node');
-
-  foreach ($bundle_info->getBundleInfo('node') as $bundle => $info) {
-    if ($moderation_info->shouldModerateEntitiesOfBundle($entity_type, $bundle)) {
-      return AccessResult::allowed();
-    }
-  }
-
-  return AccessResult::forbidden();
-}
diff --git a/moderation_dashboard.permissions.yml b/moderation_dashboard.permissions.yml
index 6909ed7..369a78d 100644
--- a/moderation_dashboard.permissions.yml
+++ b/moderation_dashboard.permissions.yml
@@ -1,3 +1,5 @@
 use moderation dashboard:
   title: 'Use the Moderation Dashboard'
   description: 'This permission is necessary to access the Moderation Dashboard.'
+view any moderation dashboard:
+  title: 'View any Moderation Dashboard'
diff --git a/moderation_dashboard.services.yml b/moderation_dashboard.services.yml
index 3175d83..a408991 100644
--- a/moderation_dashboard.services.yml
+++ b/moderation_dashboard.services.yml
@@ -1,8 +1,4 @@
 services:
-  moderation_dashboard.route_subscriber:
-    class: \Drupal\moderation_dashboard\Routing\RouteSubscriber
-    tags:
-      - { name: event_subscriber }
   moderation_dashboard.response_subscriber:
     class: Drupal\moderation_dashboard\Routing\ResponseSubscriber
     tags:
diff --git a/src/Plugin/Condition/HasModeratedContentType.php b/src/Plugin/Condition/HasModeratedContentType.php
new file mode 100644
index 0000000..722c3a9
--- /dev/null
+++ b/src/Plugin/Condition/HasModeratedContentType.php
@@ -0,0 +1,106 @@
+<?php
+
+namespace Drupal\moderation_dashboard\Plugin\Condition;
+
+use Drupal\content_moderation\ModerationInformationInterface;
+use Drupal\Core\Condition\ConditionPluginBase;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a 'Has Moderated Content Type' condition.
+ *
+ * @Condition(
+ *   id = "has_moderated_content_type",
+ *   label = @Translation("Has Moderated Content Type")
+ * )
+ */
+class HasModeratedContentType extends ConditionPluginBase implements ContainerFactoryPluginInterface  {
+
+  /**
+   * The moderation information service.
+   *
+   * @var \Drupal\content_moderation\ModerationInformationInterface
+   */
+  protected $moderationInformation;
+
+  /**
+   * The bundle information service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+   */
+  protected $bundleInfo;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * HasModeratedContentType constructor.
+   *
+   * @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\content_moderation\ModerationInformationInterface $moderation_information
+   *   The moderation information service.
+   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info
+   *   The bundle information service.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, ModerationInformationInterface $moderation_information, EntityTypeBundleInfoInterface $bundle_info, EntityTypeManagerInterface $entity_type_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->moderationInformation = $moderation_information;
+    $this->bundleInfo = $bundle_info;
+    $this->entityTypeManager = $entity_type_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('content_moderation.moderation_information'),
+      $container->get('entity_type.bundle.info'),
+      $container->get('entity_type.manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function evaluate() {
+    $entity_type = $this->entityTypeManager->getDefinition('node');
+
+    foreach ($this->bundleInfo->getBundleInfo('node') as $bundle => $info) {
+      if ($this->moderationInformation->shouldModerateEntitiesOfBundle($entity_type, $bundle)) {
+        return TRUE;
+      }
+    }
+
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function summary() {
+    if ($this->isNegated()) {
+      return $this->t("Site doesn't have moderated content type(s).");
+    }
+
+    return $this->t('Site has moderated content type(s).');
+  }
+
+}
diff --git a/src/Plugin/Condition/ModerationDashboardAccess.php b/src/Plugin/Condition/ModerationDashboardAccess.php
new file mode 100644
index 0000000..f665588
--- /dev/null
+++ b/src/Plugin/Condition/ModerationDashboardAccess.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Drupal\moderation_dashboard\Plugin\Condition;
+
+use Drupal\Core\Condition\ConditionPluginBase;
+
+/**
+ * Provides a 'Moderation Dashboard Access' condition.
+ *
+ * @Condition(
+ *   id = "moderation_dashboard_access",
+ *   label = @Translation("Moderation Dashboard Access"),
+ *   context = {
+ *     "dashboard_user" = @ContextDefinition("entity:user", label = @Translation("Dashboard owner")),
+ *     "current_user" = @ContextDefinition("entity:user", label = @Translation("Current user")),
+ *   }
+ * )
+ */
+class ModerationDashboardAccess extends ConditionPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function evaluate() {
+    $dashboard_owner = $this->getContextValue('dashboard_user');
+    $current_user = $this->getContextValue('current_user');
+
+    // If the given user doesn't have a dashboard, nobody can view it.
+    if (!$dashboard_owner->hasPermission('use moderation dashboard')) {
+      return FALSE;
+    }
+
+    // If the current user is on their own dashboard, they can view it.
+    if ($current_user->id() === $dashboard_owner->id()) {
+      return TRUE;
+    }
+
+    // But they can only view the dashboard of others with another permission.
+    return $current_user->hasPermission('view any moderation dashboard');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function summary() {
+    if ($this->isNegated()) {
+      return $this->t("User can't access moderation dashboard.");
+    }
+
+    return $this->t('User can access moderation dashboard.');
+  }
+
+}
diff --git a/src/Routing/RouteSubscriber.php b/src/Routing/RouteSubscriber.php
deleted file mode 100644
index 9a85fa9..0000000
--- a/src/Routing/RouteSubscriber.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-namespace Drupal\moderation_dashboard\Routing;
-
-use Drupal\Core\Routing\RouteSubscriberBase;
-use Drupal\Core\Routing\RoutingEvents;
-use Symfony\Component\Routing\RouteCollection;
-
-/**
- * Attaches a permission requirement to our Page Manager route.
- */
-class RouteSubscriber extends RouteSubscriberBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function alterRoutes(RouteCollection $collection) {
-    if ($route = $collection->get('page_manager.page_view_moderation_dashboard_moderation_dashboard-panels_variant-0')) {
-      $route->setRequirement('_permission', 'use moderation dashboard');
-      $route->setRequirement('_custom_access', '_moderation_dashboard_page_access');
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getSubscribedEvents() {
-    // Run after \Drupal\page_manager\Routing\PageManagerRoutes.
-    $events[RoutingEvents::ALTER][] = ['onAlterRoutes', -161];
-    return $events;
-  }
-
-}
diff --git a/tests/src/Functional/ModerationDashboardPermissionTest.php b/tests/src/Functional/ModerationDashboardPermissionTest.php
new file mode 100644
index 0000000..3069408
--- /dev/null
+++ b/tests/src/Functional/ModerationDashboardPermissionTest.php
@@ -0,0 +1,207 @@
+<?php
+
+namespace Drupal\Tests\moderation_dashboard\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
+
+/**
+ * Tests moderation dashboard permissions.
+ *
+ * @group moderation_dashboard
+ */
+class ModerationDashboardPermissionTest extends BrowserTestBase {
+
+  use ContentModerationTestTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'moderation_dashboard',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    // Create a moderated entity type.
+    $this->drupalCreateContentType([
+      'type' => 'page',
+    ]);
+    $workflow = $this->createEditorialWorkflow();
+    $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page');
+    $workflow->save();
+  }
+
+  /**
+   * The test data.
+   *
+   * @var array
+   */
+  protected $canViewOwnDashboardCases = [
+    [
+      'permissions' => ['use moderation dashboard'],
+    ],
+    [
+      'permissions' => ['view any moderation dashboard', 'use moderation dashboard'],
+    ],
+  ];
+
+  /**
+   * Tests if a user can view their dashboard with permission.
+   */
+  public function testCanViewOwnDashboard() {
+    foreach ($this->canViewOwnDashboardCases as $i => $testCase) {
+      $user = $this->createUser($testCase['permissions']);
+      $this->drupalLogin($user);
+      $this->assertSession()->addressEquals("/user/{$user->id()}/moderation/dashboard");
+      $status_code = $this->getSession()->getStatusCode();
+      $message = "#$i: expected 200, got $status_code.";
+      $this->assertEquals(200, $status_code, $message);
+    }
+  }
+
+  /**
+   * The test data.
+   *
+   * @var array
+   */
+  protected $canNotViewOwnDashboardCases = [
+    [
+      'permissions' => [],
+    ],
+    [
+      'permissions' => ['view any moderation dashboard'],
+    ],
+  ];
+
+  /**
+   * Tests that a user can't view their dashboard without permission.
+   */
+  public function testCanNotViewOwnDashboard() {
+    foreach ($this->canNotViewOwnDashboardCases as $i => $testCase) {
+      $user = $this->createUser($testCase['permissions']);
+      $this->drupalLogin($user);
+      $this->drupalGet("/user/{$user->id()}/moderation/dashboard");
+      $status_code = $this->getSession()->getStatusCode();
+      $message = "#$i: expected 403, got $status_code.";
+      $this->assertEquals(403, $status_code, $message);
+    }
+  }
+
+  /**
+   * The test data.
+   *
+   * @var array
+   */
+  protected $canViewOtherDashboardCases = [
+    [
+      'permissions_a' => ['view any moderation dashboard'],
+      'permissions_b' => ['use moderation dashboard'],
+    ],
+    [
+      'permissions_a' => ['view any moderation dashboard'],
+      'permissions_b' => ['view any moderation dashboard', 'use moderation dashboard'],
+    ],
+    [
+      'permissions_a' => ['view any moderation dashboard', 'use moderation dashboard'],
+      'permissions_b' => ['use moderation dashboard'],
+    ],
+    [
+      'permissions_a' => ['view any moderation dashboard', 'use moderation dashboard'],
+      'permissions_b' => ['view any moderation dashboard', 'use moderation dashboard'],
+    ],
+  ];
+
+  /**
+   * Tests if a user can view other dashboards with permission.
+   */
+  public function testCanViewOtherDashboard() {
+    foreach ($this->canViewOtherDashboardCases as $i => $testCase) {
+      $user_a = $this->createUser($testCase['permissions_a']);
+      $user_b = $this->createUser($testCase['permissions_b']);
+      $this->drupalLogin($user_a);
+      $this->drupalGet("/user/{$user_b->id()}/moderation/dashboard");
+      $status_code = $this->getSession()->getStatusCode();
+      $message = "#$i: expected 200, got $status_code.";
+      $this->assertEquals(200, $status_code, $message);
+    }
+  }
+
+  /**
+   * The test data.
+   *
+   * @var array
+   */
+  protected $canNotViewOtherDashboardCases = [
+    // User B doesn't have a dashboard, therefore nobody can view it.
+    [
+      'permissions_a' => [],
+      'permissions_b' => [],
+    ],
+    [
+      'permissions_a' => [],
+      'permissions_b' => ['view any moderation dashboard'],
+    ],
+    [
+      'permissions_a' => ['view any moderation dashboard'],
+      'permissions_b' => [],
+    ],
+    [
+      'permissions_a' => ['view any moderation dashboard'],
+      'permissions_b' => ['view any moderation dashboard'],
+    ],
+    [
+      'permissions_a' => ['view any moderation dashboard', 'use moderation dashboard'],
+      'permissions_b' => [],
+    ],
+    [
+      'permissions_a' => ['view any moderation dashboard', 'use moderation dashboard'],
+      'permissions_b' => ['view any moderation dashboard'],
+    ],
+    [
+      'permissions_a' => ['use moderation dashboard'],
+      'permissions_b' => [],
+    ],
+    [
+      'permissions_a' => ['use moderation dashboard'],
+      'permissions_b' => ['view any moderation dashboard'],
+    ],
+    // User A doesn't have permission to view User B's dashboard.
+    [
+      'permissions_a' => [],
+      'permissions_b' => ['use moderation dashboard'],
+    ],
+    [
+      'permissions_a' => [],
+      'permissions_b' => ['view any moderation dashboard', 'use moderation dashboard'],
+    ],
+    [
+      'permissions_a' => ['use moderation dashboard'],
+      'permissions_b' => ['use moderation dashboard'],
+    ],
+    [
+      'permissions_a' => ['use moderation dashboard'],
+      'permissions_b' => ['view any moderation dashboard', 'use moderation dashboard'],
+    ],
+  ];
+
+  /**
+   * Tests that a user can't view other dashboards without permission.
+   */
+  public function testCanNotViewOtherDashboard() {
+    foreach ($this->canNotViewOtherDashboardCases as $i => $testCase) {
+      $user_a = $this->createUser($testCase['permissions_a']);
+      $user_b = $this->createUser($testCase['permissions_b']);
+      $this->drupalLogin($user_a);
+      $this->drupalGet("/user/{$user_b->id()}/moderation/dashboard");
+      $status_code = $this->getSession()->getStatusCode();
+      $message = "#$i: expected 403, got $status_code.";
+      $this->assertEquals(403, $status_code, $message);
+    }
+  }
+
+}
