diff --git a/aleksis/apps/kort/models.py b/aleksis/apps/kort/models.py
index 2e8677e7a0173d8815063775348c781c7acb91c8..e84d0174dce201f9492bc6f298643f94f3640ec8 100644
--- a/aleksis/apps/kort/models.py
+++ b/aleksis/apps/kort/models.py
@@ -146,7 +146,9 @@ class CardPrinter(ExtensibleModel):
                 self.save()
 
     @classmethod
-    def check_online_status_for_all(cls):
+    def check_online_status_for_all(cls, qs=None):
+        if not qs:
+            qs = cls.objects.all()
         for printer in cls.objects.all():
             printer.check_online_status()
 
diff --git a/aleksis/apps/kort/rules.py b/aleksis/apps/kort/rules.py
index 706449103aa3f0c4e729fb8f5a46814ba84bd769..1a1100764429f9c4831aefed9b8bfb0556669ce2 100644
--- a/aleksis/apps/kort/rules.py
+++ b/aleksis/apps/kort/rules.py
@@ -1 +1,87 @@
-# TBD
+from rules import add_rule
+
+from aleksis.core.util.predicates import (
+    has_any_object,
+    has_global_perm,
+    has_object_perm,
+    has_person,
+)
+
+from .models import Card, CardLayout, CardPrinter
+
+view_card_printers_predicate = has_person & (
+    has_global_perm("kort.view_cardprinter") | has_any_object("kort.view_cardprinter", CardPrinter)
+)
+add_rule("kort.view_cardprinters_rule", view_card_printers_predicate)
+
+view_card_printer_predicate = has_person & (
+    has_global_perm("kort.view_cardprinter") | has_object_perm("kort.view_cardprinter")
+)
+add_rule("kort.view_cardprinter_rule", view_card_printer_predicate)
+
+create_card_printer_predicate = view_card_printers_predicate & has_global_perm(
+    "kort.add_cardprinter"
+)
+add_rule("kort.create_cardprinter_rule", create_card_printer_predicate)
+
+edit_card_printer_predicate = view_card_printer_predicate & (
+    has_global_perm("kort.change_cardprinter") | has_object_perm("kort.change_cardprinter")
+)
+add_rule("kort.edit_cardprinter_rule", edit_card_printer_predicate)
+
+delete_card_printer_predicate = view_card_printer_predicate & (
+    has_global_perm("kort.delete_cardprinter") | has_object_perm("kort.delete_cardprinter")
+)
+add_rule("kort.delete_cardprinter_rule", delete_card_printer_predicate)
+
+view_card_layouts_predicate = has_person & (
+    has_global_perm("kort.view_cardlayout") | has_any_object("kort.view_cardlayout", CardLayout)
+)
+add_rule("kort.view_cardlayouts_rule", view_card_layouts_predicate)
+
+view_card_layout_predicate = has_person & (
+    has_global_perm("kort.view_cardlayout") | has_object_perm("kort.view_cardlayout")
+)
+add_rule("kort.view_cardlayout_rule", view_card_layout_predicate)
+
+create_card_layout_predicate = view_card_layouts_predicate & has_global_perm("kort.add_cardlayout")
+add_rule("kort.create_cardlayout_rule", create_card_layout_predicate)
+
+edit_card_layout_predicate = view_card_layout_predicate & (
+    has_global_perm("kort.change_cardlayout") | has_object_perm("kort.change_cardlayout")
+)
+add_rule("kort.edit_cardlayout_rule", edit_card_layout_predicate)
+
+delete_card_layout_predicate = view_card_layout_predicate & (
+    has_global_perm("kort.delete_cardlayout") | has_object_perm("kort.delete_cardlayout")
+)
+add_rule("kort.delete_cardlayout_rule", delete_card_layout_predicate)
+
+view_cards_predicate = has_person & (
+    has_global_perm("kort.view_card") | has_any_object("kort.view_card", Card)
+)
+add_rule("kort.view_cards_rule", view_cards_predicate)
+
+view_card_predicate = has_person & (
+    has_global_perm("kort.view_card") | has_object_perm("kort.view_card")
+)
+add_rule("kort.view_card_rule", view_card_predicate)
+
+create_card_predicate = view_cards_predicate & has_global_perm("kort.add_card")
+add_rule("kort.create_card_rule", create_card_predicate)
+
+edit_card_predicate = view_card_predicate & (
+    has_global_perm("kort.change_card") | has_object_perm("kort.change_card")
+)
+add_rule("kort.edit_card_rule", edit_card_predicate)
+
+delete_card_predicate = view_card_predicate & (
+    has_global_perm("kort.delete_card") | has_object_perm("kort.delete_card")
+)
+add_rule("kort.delete_card_rule", delete_card_predicate)
+
+print_card_predicate = edit_card_predicate
+add_rule("kort.print_card_rule", print_card_predicate)
+
+deactivate_card_predicate = edit_card_predicate
+add_rule("kort.deactivate_card_rule", deactivate_card_predicate)
diff --git a/aleksis/apps/kort/templates/kort/card/actions.html b/aleksis/apps/kort/templates/kort/card/actions.html
index 6a73798fb5f10b716692f1add0a12f237704cdf0..b52ad314af9f60ab12d0fc9bc742e4ed2348c5de 100644
--- a/aleksis/apps/kort/templates/kort/card/actions.html
+++ b/aleksis/apps/kort/templates/kort/card/actions.html
@@ -1,4 +1,7 @@
-{% load i18n %}
+{% load i18n rules %}
+{% has_perm 'kort.print_card_rule' user card as can_print %}
+{% has_perm 'kort.deactivate_card_rule' user card as can_deactivate %}
+{% has_perm 'kort.delete_card_rule' user card as can_delete %}
 
 <div id="detail-modal-{{ card.pk }}" class="modal">
   <div class="modal-content">
@@ -16,7 +19,7 @@
   <i class="material-icons left iconify" data-icon="mdi:play-box-outline"></i>
   {% trans "Show" %}
 </a>
-{% if not card.deactivated %}
+{% if not card.deactivated and can_deactivate %}
   <div id="deactivate-modal-{{ card.pk }}" class="modal">
     <div class="modal-content">
       <h4>{% trans "Do you really want to deactivate the following card?" %}</h4>
@@ -38,7 +41,9 @@
     {% trans "Deactivate" %}
   </a>
 {% endif %}
+{% if can_delete %}
 <a class="btn-flat waves-effect waves-red red-text modal-trigger" href="{% url "delete_card" card.pk %}">
   <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
   {% trans "Delete" %}
-</a>
\ No newline at end of file
+</a>
+{% endif %}
diff --git a/aleksis/apps/kort/templates/kort/card/detail_content.html b/aleksis/apps/kort/templates/kort/card/detail_content.html
index e87525f8a180e380584e52f01bbb1855a56aca85..07e102e5b030da2974930fbabd85d97de3df6ca3 100644
--- a/aleksis/apps/kort/templates/kort/card/detail_content.html
+++ b/aleksis/apps/kort/templates/kort/card/detail_content.html
@@ -1,4 +1,4 @@
-{% load i18n %}
+{% load i18n rules %}
 <div class="row">
   <div class="col s12 m12 l6">
     <div class="card">
@@ -53,12 +53,15 @@
         {% trans "Show card as PDF" %}
       </a>
     {% else %}
-      <div class="row center-via-flex">
-        <a class="btn waves-effect waves-light" href="{% url "generate_card_pdf" card.pk %}">
-          <i class="material-icons left iconify" data-icon="mdi:file-pdf-box"></i>
-          {% trans "Generate card as PDF" %}
-        </a>
-      </div>
+      {% has_perm 'kort.edit_card_rule' user card as can_edit %}
+      {% if can_edit %}
+        <div class="row center-via-flex">
+          <a class="btn waves-effect waves-light" href="{% url "generate_card_pdf" card.pk %}">
+            <i class="material-icons left iconify" data-icon="mdi:file-pdf-box"></i>
+            {% trans "Generate card as PDF" %}
+          </a>
+        </div>
+      {% endif %}
     {% endif %}
   </div>
 </div>
\ No newline at end of file
diff --git a/aleksis/apps/kort/templates/kort/card/list.html b/aleksis/apps/kort/templates/kort/card/list.html
index 69da48d34adf62de715f26d562a32272c61027e0..c299e9f0761863a845331c3e227c4fd412dd9121 100644
--- a/aleksis/apps/kort/templates/kort/card/list.html
+++ b/aleksis/apps/kort/templates/kort/card/list.html
@@ -9,9 +9,9 @@
 {% block page_title %}{% blocktrans %}Cards{% endblocktrans %}{% endblock %}
 
 {% block content %}
-  {% has_perm 'core.create_card_rule' user person as can_create_person %}
+  {% has_perm 'kort.create_card_rule' user as can_create %}
 
-  {% if can_create_person %}
+  {% if can_create %}
     <a class="btn green waves-effect waves-light" href="{% url 'create_card' %}">
       <i class="material-icons left iconify" data-icon="mdi:plus"></i>
       {% trans "Issue new card(s)" %}
diff --git a/aleksis/apps/kort/templates/kort/card/print_form.html b/aleksis/apps/kort/templates/kort/card/print_form.html
index 01fef6935f959dcfc523c5c283bd509fdf362b26..6466d8fef635b9b9f73f5d1bc5f3fcd5475e3c1e 100644
--- a/aleksis/apps/kort/templates/kort/card/print_form.html
+++ b/aleksis/apps/kort/templates/kort/card/print_form.html
@@ -1,18 +1,21 @@
-{% load material_form i18n %}
-<form action="{% url "print_card" card.pk %}" method="get">
-  <div class="card">
-    <div class="card-content">
-      <div class="card-title"><i class="material-icons left iconify"
-                                 data-icon="mdi:printer-outline"></i> {% trans "Print card" %}</div>
+{% load material_form i18n rules %}
+{% has_perm 'kort.print_card_rule' user card as can_print %}
+{% if can_print %}
+  <form action="{% url "print_card" card.pk %}" method="get">
+    <div class="card">
+      <div class="card-content">
+        <div class="card-title"><i class="material-icons left iconify"
+                                   data-icon="mdi:printer-outline"></i> {% trans "Print card" %}</div>
 
-      {% csrf_token %}
-      {% form form=printer_form %}{% endform %}
+        {% csrf_token %}
+        {% form form=printer_form %}{% endform %}
+      </div>
+      <div class="card-action-light">
+        <button type="submit" class="btn waves-effect waves-light">
+          <i class="material-icons left iconify" data-icon="mdi:printer-outline"></i>
+          {% trans "Print card" %}
+        </button>
+      </div>
     </div>
-    <div class="card-action-light">
-      <button type="submit" class="btn waves-effect waves-light">
-        <i class="material-icons left iconify" data-icon="mdi:printer-outline"></i>
-        {% trans "Print card" %}
-      </button>
-    </div>
-  </div>
-</form>
+  </form>
+{% endif %}
\ No newline at end of file
diff --git a/aleksis/apps/kort/templates/kort/card_layout/actions.html b/aleksis/apps/kort/templates/kort/card_layout/actions.html
index f8220b292f37cee649303500a3e4160d58e3e1da..ed8cf0d1ad466ea86ff12ad9833fb34c7180ad33 100644
--- a/aleksis/apps/kort/templates/kort/card_layout/actions.html
+++ b/aleksis/apps/kort/templates/kort/card_layout/actions.html
@@ -1,4 +1,4 @@
-{% load i18n %}
+{% load i18n rules %}
 
 <div id="detail-modal-{{ card_layout.pk }}" class="modal">
   <div class="modal-content">
@@ -16,11 +16,20 @@
   <i class="material-icons left iconify" data-icon="mdi:play-box-outline"></i>
   {% trans "Show" %}
 </a>
-<a class="btn-flat waves-effect waves-orange orange-text modal-trigger" href="{% url "edit_card_layout" card_layout.pk %}">
-  <i class="material-icons left iconify" data-icon="mdi:pencil-outline"></i>
-  {% trans "Edit" %}
-</a>
-<a class="btn-flat waves-effect waves-red red-text modal-trigger" href="{% url "delete_card_layout" card_layout.pk %}">
-  <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
-  {% trans "Delete" %}
-</a>
\ No newline at end of file
+{% has_perm 'kort.edit_cardlayout_rule' user card_layout as can_edit %}
+{% has_perm 'kort.delete_cardlayout_rule' user card_layout as can_delete %}
+
+{% if can_edit %}
+  <a class="btn-flat waves-effect waves-orange orange-text modal-trigger"
+     href="{% url "edit_card_layout" card_layout.pk %}">
+    <i class="material-icons left iconify" data-icon="mdi:pencil-outline"></i>
+    {% trans "Edit" %}
+  </a>
+{% endif %}
+{% if can_delete %}
+  <a class="btn-flat waves-effect waves-red red-text modal-trigger"
+     href="{% url "delete_card_layout" card_layout.pk %}">
+    <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
+    {% trans "Delete" %}
+  </a>
+{% endif %}
\ No newline at end of file
diff --git a/aleksis/apps/kort/templates/kort/card_layout/detail.html b/aleksis/apps/kort/templates/kort/card_layout/detail.html
index 5a7fb24186511b3acf1d267d0eee5a1661f3df10..641cae45a6d0073c158c7b652de51eb9832cc871 100644
--- a/aleksis/apps/kort/templates/kort/card_layout/detail.html
+++ b/aleksis/apps/kort/templates/kort/card_layout/detail.html
@@ -2,7 +2,7 @@
 
 {% extends "core/base.html" %}
 
-{% load material_form i18n any_js %}
+{% load material_form i18n any_js rules %}
 
 
 {% block browser_title %}{% blocktrans %}Card Layout{% endblocktrans %}{% endblock %}
@@ -14,14 +14,22 @@
     <i class="material-icons left iconify" data-icon="mdi:arrow-left"></i>
     {% trans "Back to all layouts" %}
   </a>
-  <a class="btn waves-effect waves-light margin-bottom orange modal-trigger"
-     href="{% url "edit_card_layout" object.pk %}">
-    <i class="material-icons left iconify" data-icon="mdi:pencil-outline"></i>
-    {% trans "Edit" %}
-  </a>
-  <a class="btn waves-effect waves-light margin-bottom red modal-trigger" href="{% url "delete_card_layout" object.pk %}">
-    <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
-    {% trans "Delete" %}
-  </a>
+  {% has_perm 'kort.edit_cardlayout_rule' user object as can_edit %}
+  {% has_perm 'kort.delete_cardlayout_rule' user object as can_delete %}
+
+  {% if can_edit %}
+    <a class="btn waves-effect waves-light margin-bottom orange modal-trigger"
+       href="{% url "edit_card_layout" object.pk %}">
+      <i class="material-icons left iconify" data-icon="mdi:pencil-outline"></i>
+      {% trans "Edit" %}
+    </a>
+  {% endif %}
+  {% if can_delete %}
+    <a class="btn waves-effect waves-light margin-bottom red modal-trigger"
+       href="{% url "delete_card_layout" object.pk %}">
+      <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
+      {% trans "Delete" %}
+    </a>
+  {% endif %}
   {% include "kort/card_layout/detail_content.html" with card_layout=object %}
 {% endblock %}
diff --git a/aleksis/apps/kort/templates/kort/card_layout/list.html b/aleksis/apps/kort/templates/kort/card_layout/list.html
index c12a4bde3490e9d95062a5269f8bdbc777488dd2..2e8605403448f76683b348cea5af4a7d4d767020 100644
--- a/aleksis/apps/kort/templates/kort/card_layout/list.html
+++ b/aleksis/apps/kort/templates/kort/card_layout/list.html
@@ -9,7 +9,7 @@
 {% block page_title %}{% blocktrans %}Card layouts{% endblocktrans %}{% endblock %}
 
 {% block content %}
-  {% has_perm 'core.create_cardlayout_rule' user person as can_create %}
+  {% has_perm 'kort.create_cardlayout_rule' user as can_create %}
 
   {% if can_create %}
     <a class="btn green waves-effect waves-light" href="{% url 'create_card_layout' %}">
diff --git a/aleksis/apps/kort/templates/kort/printer/actions.html b/aleksis/apps/kort/templates/kort/printer/actions.html
index 74f1bccbaafe048280e28a20e29195c346b1a54f..97d6296487c5714f7081b20089826b8f8f3dec67 100644
--- a/aleksis/apps/kort/templates/kort/printer/actions.html
+++ b/aleksis/apps/kort/templates/kort/printer/actions.html
@@ -1,4 +1,4 @@
-{% load i18n %}
+{% load i18n rules %}
 
 <div id="detail-modal-{{ printer.pk }}" class="modal">
   <div class="modal-content">
@@ -16,11 +16,20 @@
   <i class="material-icons left iconify" data-icon="mdi:play-box-outline"></i>
   {% trans "Show" %}
 </a>
-<a class="btn-flat waves-effect waves-orange orange-text modal-trigger" href="{% url "edit_card_printer" printer.pk %}">
-  <i class="material-icons left iconify" data-icon="mdi:pencil-outline"></i>
-  {% trans "Edit" %}
-</a>
-<a class="btn-flat waves-effect waves-red red-text modal-trigger" href="{% url "delete_card_printer" printer.pk %}">
-  <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
-  {% trans "Delete" %}
-</a>
\ No newline at end of file
+
+{% has_perm 'kort.edit_cardprinter_rule' user printer as can_edit %}
+{% has_perm 'kort.delete_cardprinter_rule' user printer as can_delete %}
+
+{% if can_edit %}
+  <a class="btn-flat waves-effect waves-orange orange-text modal-trigger"
+     href="{% url "edit_card_printer" printer.pk %}">
+    <i class="material-icons left iconify" data-icon="mdi:pencil-outline"></i>
+    {% trans "Edit" %}
+  </a>
+{% endif %}
+{% if can_delete %}
+  <a class="btn-flat waves-effect waves-red red-text modal-trigger" href="{% url "delete_card_printer" printer.pk %}">
+    <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
+    {% trans "Delete" %}
+  </a>
+{% endif %}
\ No newline at end of file
diff --git a/aleksis/apps/kort/templates/kort/printer/detail.html b/aleksis/apps/kort/templates/kort/printer/detail.html
index 303b6674c9b6941b30b8e3fba54c2b58ae6a7793..4df219cab1ca0b107da5964e6b079c84b2e3ed46 100644
--- a/aleksis/apps/kort/templates/kort/printer/detail.html
+++ b/aleksis/apps/kort/templates/kort/printer/detail.html
@@ -2,7 +2,7 @@
 
 {% extends "core/base.html" %}
 
-{% load material_form i18n any_js %}
+{% load material_form i18n any_js rules %}
 
 
 {% block browser_title %}{% blocktrans %}Card Printer{% endblocktrans %}{% endblock %}
@@ -14,14 +14,22 @@
     <i class="material-icons left iconify" data-icon="mdi:arrow-left"></i>
     {% trans "Back to all printers" %}
   </a>
-  <a class="btn waves-effect waves-light margin-bottom orange modal-trigger"
-     href="{% url "edit_card_printer" object.pk %}">
-    <i class="material-icons left iconify" data-icon="mdi:pencil-outline"></i>
-    {% trans "Edit" %}
-  </a>
-  <a class="btn waves-effect waves-light margin-bottom red modal-trigger" href="{% url "delete_card_printer" object.pk %}">
-    <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
-    {% trans "Delete" %}
-  </a>
+  {% has_perm 'kort.edit_cardprinter_rule' user printer as can_edit %}
+  {% has_perm 'kort.delete_cardprinter_rule' user printer as can_delete %}
+
+  {% if can_edit %}
+    <a class="btn waves-effect waves-light margin-bottom orange modal-trigger"
+       href="{% url "edit_card_printer" object.pk %}">
+      <i class="material-icons left iconify" data-icon="mdi:pencil-outline"></i>
+      {% trans "Edit" %}
+    </a>
+  {% endif %}
+  {% if can_delete %}
+    <a class="btn waves-effect waves-light margin-bottom red modal-trigger"
+       href="{% url "delete_card_printer" object.pk %}">
+      <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
+      {% trans "Delete" %}
+    </a>
+  {% endif %}
   {% include "kort/printer/detail_content.html" with printer=object %}
 {% endblock %}
diff --git a/aleksis/apps/kort/templates/kort/printer/list.html b/aleksis/apps/kort/templates/kort/printer/list.html
index 014df87d08e4f8fdadcc590bca0ebb6fe1b87d77..f61cee0d5359107ea23f3cfdd04904c34fe587d3 100644
--- a/aleksis/apps/kort/templates/kort/printer/list.html
+++ b/aleksis/apps/kort/templates/kort/printer/list.html
@@ -9,9 +9,9 @@
 {% block page_title %}{% blocktrans %}Card printers{% endblocktrans %}{% endblock %}
 
 {% block content %}
-  {% has_perm 'core.create_cardprinter_rule' user person as can_create_person %}
+  {% has_perm 'kort.create_cardprinter_rule' user as can_create %}
 
-  {% if can_create_person %}
+  {% if can_create %}
     <a class="btn green waves-effect waves-light" href="{% url 'create_card_printer' %}">
       <i class="material-icons left iconify" data-icon="mdi:plus"></i>
       {% trans "Register new card printer" %}
diff --git a/aleksis/apps/kort/urls.py b/aleksis/apps/kort/urls.py
index 7c5001b4c2c6f4cddc1beb33c1b1701a8ebde172..e9809ccdf3a377aa267b5caf62ffd4cdd8c38b3a 100644
--- a/aleksis/apps/kort/urls.py
+++ b/aleksis/apps/kort/urls.py
@@ -3,7 +3,6 @@ from django.urls import path
 from . import api, views
 
 urlpatterns = [
-    path("test", views.TestPDFView.as_view(), name="test_pdf"),
     path("cards/", views.CardListView.as_view(), name="cards"),
     path("cards/create/", views.CardIssueView.as_view(), name="create_card"),
     path("cards/<int:pk>/", views.CardDetailView.as_view(), name="card"),
diff --git a/aleksis/apps/kort/views.py b/aleksis/apps/kort/views.py
index a168782a66ce19da38ee25d88d878824bd7a2308..a9b1b45111b2ce40d618c461a3e00669743e216a 100644
--- a/aleksis/apps/kort/views.py
+++ b/aleksis/apps/kort/views.py
@@ -4,7 +4,7 @@ from django.contrib import messages
 from django.db.models import Count, Q, QuerySet
 from django.forms import Form
 from django.http import HttpRequest, HttpResponse
-from django.shortcuts import get_object_or_404, redirect, render
+from django.shortcuts import get_object_or_404, redirect
 from django.urls import reverse, reverse_lazy
 from django.utils.translation import gettext as _
 from django.views import View
@@ -12,6 +12,7 @@ from django.views.generic.detail import DetailView, SingleObjectMixin
 
 from django_tables2 import RequestConfig, SingleTableView, table_factory
 from formtools.wizard.views import CookieWizardView
+from guardian.shortcuts import get_objects_for_user
 from reversion.views import RevisionMixin
 from rules.contrib.views import PermissionRequiredMixin
 
@@ -33,20 +34,6 @@ from aleksis.apps.kort.tables import (
 from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView
 from aleksis.core.models import Person
 from aleksis.core.util.celery_progress import render_progress_page
-from aleksis.core.views import RenderPDFView
-
-
-class TestPDFView(RenderPDFView):
-    template_name = "kort/pdf.html"
-
-    def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
-        context = self.get_context_data(**kwargs)
-        return render(request, self.template_name, context)
-
-    def get_context_data(self, **kwargs):
-        context = super().get_context_data(**kwargs)
-        context["title"] = "Test PDF"
-        return context
 
 
 class PrinterSelectMixin:
@@ -60,19 +47,22 @@ class PrinterSelectMixin:
 class CardListView(PermissionRequiredMixin, RevisionMixin, PrinterSelectMixin, SingleTableView):
     """List view for all cards."""
 
-    permission_required = "core.view_cards_rule"
+    permission_required = "kort.view_cards_rule"
     template_name = "kort/card/list.html"
     model = Card
     table_class = CardTable
 
     def get_queryset(self):
-        return Card.objects.order_by("-pk")
+        qs = Card.objects.order_by("-pk")
+        if not self.request.user.has_perm("kort.view_card"):
+            return get_objects_for_user(self.request.user, "kort.view_card", qs)
+        return qs
 
 
 class CardIssueView(PermissionRequiredMixin, RevisionMixin, CookieWizardView):
     """View used to issue one or more cards."""
 
-    permission_required = "core.create_card_rule"
+    permission_required = "kort.create_card_rule"
     context_object_name = "application"
     template_name = "kort/card/issue.html"
     form_list = [CardIssueForm, CardIssueFinishForm]
@@ -161,7 +151,7 @@ class CardIssueView(PermissionRequiredMixin, RevisionMixin, CookieWizardView):
 class CardDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDeleteView):
     """View used to delete a card."""
 
-    permission_required = "core.delete_card_rule"
+    permission_required = "kort.delete_card_rule"
     success_url = reverse_lazy("cards")
     template_name = "kort/card/delete.html"
     model = Card
@@ -171,7 +161,7 @@ class CardDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDeleteView)
 class CardDeactivateView(PermissionRequiredMixin, RevisionMixin, SingleObjectMixin, View):
     """View used to deactivate a card."""
 
-    permission_required = "core.delete_card_rule"
+    permission_required = "kort.deactivate_card_rule"
     model = Card
     success_url = reverse_lazy("cards")
 
@@ -185,7 +175,7 @@ class CardDeactivateView(PermissionRequiredMixin, RevisionMixin, SingleObjectMix
 class CardPrintView(PermissionRequiredMixin, RevisionMixin, SingleObjectMixin, View):
     """View used to create a print job for a card."""
 
-    permission_required = "core.delete_card_rule"
+    permission_required = "kort.print_card_rule"
     model = Card
     success_url = reverse_lazy("cards")
 
@@ -214,13 +204,13 @@ class CardPrintView(PermissionRequiredMixin, RevisionMixin, SingleObjectMixin, V
 
 
 class CardDetailView(PermissionRequiredMixin, RevisionMixin, PrinterSelectMixin, DetailView):
-    permission_required = "core.view_card_rule"
+    permission_required = "kort.view_card_rule"
     model = Card
     template_name = "kort/card/detail.html"
 
 
 class CardGeneratePDFView(PermissionRequiredMixin, RevisionMixin, SingleObjectMixin, View):
-    permission_required = "views.view_card_rule"
+    permission_required = "views.edit_card_rule"
     model = Card
 
     def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
@@ -253,28 +243,32 @@ class CardGeneratePDFView(PermissionRequiredMixin, RevisionMixin, SingleObjectMi
 class CardPrinterListView(PermissionRequiredMixin, RevisionMixin, SingleTableView):
     """List view for all card printers."""
 
-    permission_required = "core.view_cardprinters_rule"
+    permission_required = "kort.view_cardprinters_rule"
     template_name = "kort/printer/list.html"
     model = CardPrinter
     table_class = CardPrinterTable
 
     def get_queryset(self):
-        return CardPrinter.objects.all().annotate(
+        qs = CardPrinter.objects.all().annotate(
             jobs_count=Count(
                 "jobs", filter=~Q(jobs__status__in=[PrintStatus.FINISHED, PrintStatus.FAILED])
             )
         )
 
+        if not self.request.user.has_perm("kort.view_cardprinter"):
+            return get_objects_for_user(self.request.user, "kort.view_cardprinter", CardPrinter)
+        return qs
+
     def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
-        CardPrinter.check_online_status_for_all()
+        CardPrinter.check_online_status_for_all(self.get_queryset())
         return context
 
 
 class CardPrinterCreateView(PermissionRequiredMixin, RevisionMixin, AdvancedCreateView):
     """View used to create a card printer."""
 
-    permission_required = "core.create_cardprinter_rule"
+    permission_required = "kort.create_cardprinter_rule"
     template_name = "kort/printer/create.html"
     form_class = CardPrinterForm
     model = CardPrinter
@@ -287,7 +281,7 @@ class CardPrinterCreateView(PermissionRequiredMixin, RevisionMixin, AdvancedCrea
 class CardPrinterEditView(PermissionRequiredMixin, RevisionMixin, AdvancedEditView):
     """View used to edit a card printer."""
 
-    permission_required = "core.edit_cardprinter_rule"
+    permission_required = "kort.edit_cardprinter_rule"
     template_name = "kort/printer/edit.html"
     form_class = CardPrinterForm
     model = CardPrinter
@@ -300,7 +294,7 @@ class CardPrinterEditView(PermissionRequiredMixin, RevisionMixin, AdvancedEditVi
 class CardPrinterDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDeleteView):
     """View used to delete a card printer."""
 
-    permission_required = "core.delete_cardprinter_rule"
+    permission_required = "kort.delete_cardprinter_rule"
     success_url = reverse_lazy("card_printers")
     template_name = "kort/printer/delete.html"
     model = CardPrinter
@@ -308,7 +302,7 @@ class CardPrinterDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDele
 
 
 class CardPrinterDetailView(PermissionRequiredMixin, RevisionMixin, DetailView):
-    permission_required = "core.view_cardprinter_rule"
+    permission_required = "kort.view_cardprinter_rule"
     model = CardPrinter
     template_name = "kort/printer/detail.html"
 
@@ -346,18 +340,24 @@ class CardLayoutFormMixin:
 class CardLayoutListView(PermissionRequiredMixin, RevisionMixin, SingleTableView):
     """List view for all card layouts."""
 
-    permission_required = "core.view_cardlayouts_rule"
+    permission_required = "kort.view_cardlayouts_rule"
     template_name = "kort/card_layout/list.html"
     model = CardLayout
     table_class = CardLayoutTable
 
+    def get_queryset(self):
+        qs = super().get_queryset()
+        if not self.request.user.has_perm("kort.view_cardlayout"):
+            return get_objects_for_user(self.request.user, "kort.view_cardlayout", CardPrinter)
+        return qs
+
 
 class CardLayoutCreateView(
     PermissionRequiredMixin, CardLayoutFormMixin, RevisionMixin, AdvancedCreateView
 ):
     """View used to create a card layout."""
 
-    permission_required = "core.create_cardlayout_rule"
+    permission_required = "kort.create_cardlayout_rule"
     template_name = "kort/card_layout/create.html"
     form_class = CardLayoutForm
     model = CardLayout
@@ -375,7 +375,7 @@ class CardLayoutEditView(
 ):
     """View used to edit a card layout."""
 
-    permission_required = "core.edit_cardlayout_rule"
+    permission_required = "kort.edit_cardlayout_rule"
     template_name = "kort/card_layout/edit.html"
     form_class = CardLayoutForm
     model = CardLayout
@@ -388,7 +388,7 @@ class CardLayoutEditView(
 class CardLayoutDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDeleteView):
     """View used to delete a card layout."""
 
-    permission_required = "core.delete_cardlayout_rule"
+    permission_required = "kort.delete_cardlayout_rule"
     success_url = reverse_lazy("card_layouts")
     template_name = "kort/card_layout/delete.html"
     model = CardLayout
@@ -396,13 +396,13 @@ class CardLayoutDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDelet
 
 
 class CardLayoutDetailView(PermissionRequiredMixin, RevisionMixin, DetailView):
-    permission_required = "core.view_cardlayout_rule"
+    permission_required = "kort.view_cardlayout_rule"
     model = CardLayout
     template_name = "kort/card_layout/detail.html"
 
 
 class CardPrinterConfigView(PermissionRequiredMixin, RevisionMixin, SingleObjectMixin, View):
-    permission_required = "core.view_cardprinter_rule"
+    permission_required = "kort.view_cardprinter_rule"
     model = CardPrinter
 
     def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: