diff --git a/jsonnet/kube-prometheus/components/grafana.libsonnet b/jsonnet/kube-prometheus/components/grafana.libsonnet
index d6d8cc8d675b754da549e10e53ef8cd756e0b1cf..a46b0845919625505b619dc9a1370856048717e5 100644
--- a/jsonnet/kube-prometheus/components/grafana.libsonnet
+++ b/jsonnet/kube-prometheus/components/grafana.libsonnet
@@ -24,6 +24,12 @@ local defaults = {
     if !std.setMember(labelName, ['app.kubernetes.io/version'])
   },
   prometheusName:: error 'must provide prometheus name',
+  mixin: {
+    ruleLabels: {},
+    _config: {
+      runbookURLPattern: 'https://runbooks.prometheus-operator.dev/runbooks/grafana/%s',
+    },
+  },
 };
 
 function(params)
@@ -40,6 +46,27 @@ function(params)
       labels: g._config.commonLabels,
     },
 
+    mixin::
+      (import 'github.com/grafana/grafana/grafana-mixin/mixin.libsonnet') +
+      (import 'github.com/kubernetes-monitoring/kubernetes-mixin/lib/add-runbook-links.libsonnet') + {
+        _config+:: g._config.mixin._config,
+      },
+
+    prometheusRule: {
+      apiVersion: 'monitoring.coreos.com/v1',
+      kind: 'PrometheusRule',
+      metadata: {
+        labels: g._config.commonLabels + g._config.mixin.ruleLabels,
+        name: g._config.name + '-rules',
+        namespace: g._config.namespace,
+      },
+      spec: {
+        local r = if std.objectHasAll(g.mixin, 'prometheusRules') then g.mixin.prometheusRules.groups else [],
+        local a = if std.objectHasAll(g.mixin, 'prometheusAlerts') then g.mixin.prometheusAlerts.groups else [],
+        groups: a + r,
+      },
+    },
+
     serviceMonitor: {
       apiVersion: 'monitoring.coreos.com/v1',
       kind: 'ServiceMonitor',
diff --git a/jsonnet/kube-prometheus/jsonnetfile.json b/jsonnet/kube-prometheus/jsonnetfile.json
index c9b9c67e661d1153fa2b40e2a0f86eea198b73a0..b2d99cc7718fc1dfcaa903d36b8c61a3a0dce98d 100644
--- a/jsonnet/kube-prometheus/jsonnetfile.json
+++ b/jsonnet/kube-prometheus/jsonnetfile.json
@@ -10,6 +10,16 @@
       },
       "version": "master"
     },
+    {
+      "source": {
+        "git": {
+          "remote": "https://github.com/grafana/grafana",
+          "subdir": "grafana-mixin"
+        }
+      },
+      "version": "main",
+      "name": "grafana-mixin"
+    },
     {
       "source": {
         "git": {
diff --git a/jsonnet/kube-prometheus/main.libsonnet b/jsonnet/kube-prometheus/main.libsonnet
index 9dc5a334c508b935c13f1f50df6b8ef91f30ac89..3349c8f6e9951573f15695891cc0770a46c0b792 100644
--- a/jsonnet/kube-prometheus/main.libsonnet
+++ b/jsonnet/kube-prometheus/main.libsonnet
@@ -70,7 +70,12 @@ local utils = import './lib/utils.libsonnet';
       image: $.values.common.images.grafana,
       prometheusName: $.values.prometheus.name,
       // TODO(paulfantom) This should be done by iterating over all objects and looking for object.mixin.grafanaDashboards
-      dashboards: $.nodeExporter.mixin.grafanaDashboards + $.prometheus.mixin.grafanaDashboards + $.kubernetesControlPlane.mixin.grafanaDashboards + $.alertmanager.mixin.grafanaDashboards,
+      dashboards: $.nodeExporter.mixin.grafanaDashboards +
+                  $.prometheus.mixin.grafanaDashboards +
+                  $.kubernetesControlPlane.mixin.grafanaDashboards +
+                  $.alertmanager.mixin.grafanaDashboards +
+                  $.grafana.mixin.grafanaDashboards,
+      mixin+: { ruleLabels: $.values.common.ruleLabels },
     },
     kubeStateMetrics: {
       namespace: $.values.common.namespace,