diff --git a/example.jsonnet b/example.jsonnet
index a459460db2451ce5548f093b9b01e3fb92a1dbf3..94a40b7086fc539bdd3bd0f8afa702c7ba44150c 100644
--- a/example.jsonnet
+++ b/example.jsonnet
@@ -14,17 +14,20 @@ local kp =
     },
   };
 
-{ ['setup/0namespace-' + name]: kp.kubePrometheus[name] for name in std.objectFields(kp.kubePrometheus) } +
+{ ['setup/0namespace-namespace']: kp.kubePrometheus.namespace } +
 {
   ['setup/prometheus-operator-' + name]: kp.prometheusOperator[name]
-  for name in std.filter((function(name) name != 'serviceMonitor'), std.objectFields(kp.prometheusOperator))
+  for name in std.filter((function(name) name != 'serviceMonitor' && name != 'prometheusRule'), std.objectFields(kp.prometheusOperator))
 } +
-// serviceMonitor is separated so that it can be created after the CRDs are ready
+// serviceMonitor and prometheusRule are separated so that they can be created after the CRDs are ready
 { 'prometheus-operator-serviceMonitor': kp.prometheusOperator.serviceMonitor } +
+{ 'prometheus-operator-prometheusRule': kp.prometheusOperator.prometheusRule } +
+{ 'kube-prometheus-prometheusRule': kp.kubePrometheus.prometheusRule } +
 { ['node-exporter-' + name]: kp.nodeExporter[name] for name in std.objectFields(kp.nodeExporter) } +
 { ['blackbox-exporter-' + name]: kp.blackboxExporter[name] for name in std.objectFields(kp.blackboxExporter) } +
 { ['kube-state-metrics-' + name]: kp.kubeStateMetrics[name] for name in std.objectFields(kp.kubeStateMetrics) } +
 { ['alertmanager-' + name]: kp.alertmanager[name] for name in std.objectFields(kp.alertmanager) } +
 { ['prometheus-' + name]: kp.prometheus[name] for name in std.objectFields(kp.prometheus) } +
 { ['prometheus-adapter-' + name]: kp.prometheusAdapter[name] for name in std.objectFields(kp.prometheusAdapter) } +
-{ ['grafana-' + name]: kp.grafana[name] for name in std.objectFields(kp.grafana) }
+{ ['grafana-' + name]: kp.grafana[name] for name in std.objectFields(kp.grafana) } +
+{ ['kubernetes-' + name]: kp.kubernetesMixin[name] for name in std.objectFields(kp.kubernetesMixin) }
diff --git a/jsonnet/kube-prometheus/kube-prometheus.libsonnet b/jsonnet/kube-prometheus/kube-prometheus.libsonnet
index 6688f023fde3cd7e087af92ed80dbe439b5be16a..6d8710a8ee9818a35ca1d8f00a01351ec0fc5c61 100644
--- a/jsonnet/kube-prometheus/kube-prometheus.libsonnet
+++ b/jsonnet/kube-prometheus/kube-prometheus.libsonnet
@@ -1,13 +1,14 @@
 local alertmanager = import './alertmanager/alertmanager.libsonnet';
 local blackboxExporter = import './blackbox-exporter/blackbox-exporter.libsonnet';
+local customMixin = import './mixin/custom.libsonnet';
 local kubeStateMetrics = import './kube-state-metrics/kube-state-metrics.libsonnet';
+local kubernetesMixin = import './mixin/kubernetes.libsonnet';
 local nodeExporter = import './node-exporter/node-exporter.libsonnet';
 local prometheusAdapter = import './prometheus-adapter/prometheus-adapter.libsonnet';
 local prometheusOperator = import './prometheus-operator/prometheus-operator.libsonnet';
 local prometheus = import './prometheus/prometheus.libsonnet';
 local prometheusOperator = import './prometheus-operator/prometheus-operator.libsonnet';
 
-local monitoringMixins = import './mixins/monitoring-mixins.libsonnet';
 
 (import 'github.com/brancz/kubernetes-grafana/grafana/grafana.libsonnet') +
 {
@@ -69,25 +70,18 @@ local monitoringMixins = import './mixins/monitoring-mixins.libsonnet';
       ruleLabels: $._config.ruleLabels,
     },
   }),
-  mixins+:: monitoringMixins({
+  kubernetesMixin: kubernetesMixin({
     namespace: $._config.namespace,
+    mixin+: {
+      ruleLabels: $._config.ruleLabels,
+    },
   }),
-
-  // FIXME(paulfantom) Remove this variable by moving each mixin to its own component
-  // Example: node_exporter mixin could be added in ./node-exporter/node-exporter.libsonnet
-  allRules::
-    //$.mixins.nodeExporter.prometheusRules +
-    $.mixins.kubernetes.prometheusRules +
-    $.mixins.base.prometheusRules +
-    //$.mixins.kubeStateMetrics.prometheusAlerts +
-    //$.mixins.nodeExporter.prometheusAlerts +
-    //$.mixins.alertmanager.prometheusAlerts +
-    //$.mixins.prometheusOperator.prometheusAlerts +
-    $.mixins.kubernetes.prometheusAlerts +
-    //$.mixins.prometheus.prometheusAlerts +
-    $.mixins.base.prometheusAlerts,
-
-  kubePrometheus+:: {
+  kubePrometheus: customMixin({
+    namespace: $._config.namespace,
+    mixin+: {
+      ruleLabels: $._config.ruleLabels,
+    },
+  }) + {
     namespace: {
       apiVersion: 'v1',
       kind: 'Namespace',
@@ -147,9 +141,9 @@ local monitoringMixins = import './mixins/monitoring-mixins.libsonnet';
       },
       // FIXME(paulfantom): Same as with rules and alerts.
       // This should be gathering all dashboards from components without having to enumerate all dashboards.
-      dashboards:
+      dashboards: {},
         //$.mixins.nodeExporter.grafanaDashboards +
-        $.mixins.kubernetes.grafanaDashboards,
+        //$.mixins.kubernetes.grafanaDashboards,
       //$.mixins.prometheus.grafanaDashboards,
     },
   },
diff --git a/jsonnet/kube-prometheus/alerts/alerts.libsonnet b/jsonnet/kube-prometheus/mixin/alerts/alerts.libsonnet
similarity index 100%
rename from jsonnet/kube-prometheus/alerts/alerts.libsonnet
rename to jsonnet/kube-prometheus/mixin/alerts/alerts.libsonnet
diff --git a/jsonnet/kube-prometheus/alerts/general.libsonnet b/jsonnet/kube-prometheus/mixin/alerts/general.libsonnet
similarity index 100%
rename from jsonnet/kube-prometheus/alerts/general.libsonnet
rename to jsonnet/kube-prometheus/mixin/alerts/general.libsonnet
diff --git a/jsonnet/kube-prometheus/alerts/node.libsonnet b/jsonnet/kube-prometheus/mixin/alerts/node.libsonnet
similarity index 100%
rename from jsonnet/kube-prometheus/alerts/node.libsonnet
rename to jsonnet/kube-prometheus/mixin/alerts/node.libsonnet
diff --git a/jsonnet/kube-prometheus/alerts/tests.yaml b/jsonnet/kube-prometheus/mixin/alerts/tests.yaml
similarity index 100%
rename from jsonnet/kube-prometheus/alerts/tests.yaml
rename to jsonnet/kube-prometheus/mixin/alerts/tests.yaml
diff --git a/jsonnet/kube-prometheus/mixin/custom.libsonnet b/jsonnet/kube-prometheus/mixin/custom.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..d1c0b086c4aad7fe42ef362d615586bb3d5a9307
--- /dev/null
+++ b/jsonnet/kube-prometheus/mixin/custom.libsonnet
@@ -0,0 +1,42 @@
+local defaults = {
+  name: 'kube-prometheus',
+  namespace: error 'must provide namespace',
+  commonLabels:: {
+    'app.kubernetes.io/name': 'kube-prometheus',
+    'app.kubernetes.io/component': 'exporter',
+    'app.kubernetes.io/part-of': 'kube-prometheus',
+  },
+  mixin: {
+    ruleLabels: {},
+    _config: {
+        nodeExporterSelector: 'job="node-exporter"',
+        hostNetworkInterfaceSelector: 'device!~"veth.+"',
+      },
+  },
+};
+
+function(params) {
+  local m = self,
+  config:: defaults + params,
+
+  local alertsandrules = (import './alerts/alerts.libsonnet') + (import './rules/rules.libsonnet'),
+
+  mixin:: alertsandrules {
+    _config+:: m.config.mixin._config,
+  },
+
+  prometheusRule: {
+    apiVersion: 'monitoring.coreos.com/v1',
+    kind: 'PrometheusRule',
+    metadata: {
+      labels: m.config.commonLabels + m.config.mixin.ruleLabels,
+      name: m.config.name + '-rules',
+      namespace: m.config.namespace,
+    },
+    spec: {
+      local r = if std.objectHasAll(m.mixin, 'prometheusRules') then m.mixin.prometheusRules else {},
+      local a = if std.objectHasAll(m.mixin, 'prometheusAlerts') then m.mixin.prometheusAlerts else {},
+      groups: a + r,
+    },
+  },
+}
diff --git a/jsonnet/kube-prometheus/mixin/kubernetes.libsonnet b/jsonnet/kube-prometheus/mixin/kubernetes.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..b3bc563e37901b3df9b6c85d6a966ded297c610e
--- /dev/null
+++ b/jsonnet/kube-prometheus/mixin/kubernetes.libsonnet
@@ -0,0 +1,49 @@
+local defaults = {
+  name: 'kubernetes',
+  namespace: error 'must provide namespace',
+  commonLabels:: {
+    'app.kubernetes.io/name': 'kube-prometheus',
+    'app.kubernetes.io/component': 'exporter',
+    'app.kubernetes.io/part-of': 'kube-prometheus',
+  },
+  mixin: {
+    ruleLabels: {},
+    _config: {
+        cadvisorSelector: 'job="kubelet", metrics_path="/metrics/cadvisor"',
+        kubeletSelector: 'job="kubelet", metrics_path="/metrics"',
+        kubeStateMetricsSelector: 'job="kube-state-metrics"',
+        nodeExporterSelector: 'job="node-exporter"',
+        kubeSchedulerSelector: 'job="kube-scheduler"',
+        kubeControllerManagerSelector: 'job="kube-controller-manager"',
+        kubeApiserverSelector: 'job="apiserver"',
+        podLabel: 'pod',
+        runbookURLPattern: 'https://github.com/prometheus-operator/kube-prometheus/wiki/%s',
+        diskDeviceSelector: 'device=~"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+"',
+        hostNetworkInterfaceSelector: 'device!~"veth.+"',
+    },
+  },
+};
+
+function(params) {
+  local m = self,
+  config:: defaults + params,
+
+  mixin:: (import 'github.com/kubernetes-monitoring/kubernetes-mixin/mixin.libsonnet') {
+    _config+:: m.config.mixin._config,
+  },
+
+  prometheusRule: {
+    apiVersion: 'monitoring.coreos.com/v1',
+    kind: 'PrometheusRule',
+    metadata: {
+      labels: m.config.commonLabels + m.config.mixin.ruleLabels,
+      name: m.config.name + '-rules',
+      namespace: m.config.namespace,
+    },
+    spec: {
+      local r = if std.objectHasAll(m.mixin, 'prometheusRules') then m.mixin.prometheusRules else {},
+      local a = if std.objectHasAll(m.mixin, 'prometheusAlerts') then m.mixin.prometheusAlerts else {},
+      groups: a + r,
+    },
+  },
+}
diff --git a/jsonnet/kube-prometheus/rules/general.libsonnet b/jsonnet/kube-prometheus/mixin/rules/general.libsonnet
similarity index 100%
rename from jsonnet/kube-prometheus/rules/general.libsonnet
rename to jsonnet/kube-prometheus/mixin/rules/general.libsonnet
diff --git a/jsonnet/kube-prometheus/rules/node-rules.libsonnet b/jsonnet/kube-prometheus/mixin/rules/node-rules.libsonnet
similarity index 100%
rename from jsonnet/kube-prometheus/rules/node-rules.libsonnet
rename to jsonnet/kube-prometheus/mixin/rules/node-rules.libsonnet
diff --git a/jsonnet/kube-prometheus/rules/rules.libsonnet b/jsonnet/kube-prometheus/mixin/rules/rules.libsonnet
similarity index 100%
rename from jsonnet/kube-prometheus/rules/rules.libsonnet
rename to jsonnet/kube-prometheus/mixin/rules/rules.libsonnet
diff --git a/jsonnet/kube-prometheus/mixins/monitoring-mixins.libsonnet b/jsonnet/kube-prometheus/mixins/monitoring-mixins.libsonnet
deleted file mode 100644
index 95b88db6750948d3c4e6ac211705171f5035ad4f..0000000000000000000000000000000000000000
--- a/jsonnet/kube-prometheus/mixins/monitoring-mixins.libsonnet
+++ /dev/null
@@ -1,35 +0,0 @@
-local defaults = {
-  namespace: error 'must provide namespace',
-};
-
-function(params) {
-  local m = self,
-  config:: defaults + params,
-  base+:
-    (import '../alerts/general.libsonnet') +
-    (import '../alerts/node.libsonnet') +
-    (import '../rules/node-rules.libsonnet') +
-    (import '../rules/general.libsonnet') {
-      _config+:: {
-        nodeExporterSelector: 'job="node-exporter"',
-        hostNetworkInterfaceSelector: 'device!~"veth.+"',
-      },
-    },
-
-  kubernetes:
-    (import 'github.com/kubernetes-monitoring/kubernetes-mixin/mixin.libsonnet') {
-      _config+:: {
-        cadvisorSelector: 'job="kubelet", metrics_path="/metrics/cadvisor"',
-        kubeletSelector: 'job="kubelet", metrics_path="/metrics"',
-        kubeStateMetricsSelector: 'job="kube-state-metrics"',
-        nodeExporterSelector: 'job="node-exporter"',
-        kubeSchedulerSelector: 'job="kube-scheduler"',
-        kubeControllerManagerSelector: 'job="kube-controller-manager"',
-        kubeApiserverSelector: 'job="apiserver"',
-        podLabel: 'pod',
-        runbookURLPattern: 'https://github.com/prometheus-operator/kube-prometheus/wiki/%s',
-        diskDeviceSelector: 'device=~"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+"',
-        hostNetworkInterfaceSelector: 'device!~"veth.+"',
-      },
-    },
-}