diff --git a/Makefile b/Makefile
index c7f2a75..a3d71dc 100644
--- a/Makefile
+++ b/Makefile
@@ -34,6 +34,14 @@ MANPAGE_HEADERS := $(sort $(wildcard $(MANDIR)*.h))
 MANPAGE_SOURCES := $(sort $(wildcard $(MANDIR)*.[012345678].pp))
 INITRD_HEADERS := $(sort $(wildcard $(INITRDDIR)*.h))
 
+ifdef TZPFMS_PASSPHRASE_HELPER
+DEF_TPH := -DTZPFMS_PASSPHRASE_HELPER='$(TZPFMS_PASSPHRASE_HELPER)'
+endif
+ifdef TZPFMS_PASSPHRASE_HELPER_MAN
+DEF_TPH_MAN := .Pp\nDefault:\n.No '\'' Ns $(TZPFMS_PASSPHRASE_HELPER_MAN) Ns '\'' .
+else
+DEF_TPH_MAN ?= .
+endif
 
 .PHONY : all clean build shellcheck i-t dracut manpages htmlpages
 .SECONDARY:
@@ -68,7 +76,7 @@ $(OUTDIR)initramfs-tools/usr/share/tzpfms/initramfs-tools-zfs-patch.sh: $(INITRD
 # Can't put it at the very top, since man(1) only loads mdoc *after* the first mdoc macro (.Dd in our case)
 $(OUTDIR)man/% : $(MANDIR)%.pp $(MANPAGE_HEADERS)
 	@mkdir -p $(dir $@)
-	$(AWK) -f pp.awk $< | $(AWK) '/^$$/ {prev_empty=1; next} $$1 == "#" && $$2 ~ /^[0-9]*$$/ {prev_empty=0; next}  {if(prev_empty) print ""; prev_empty=0; print}' | $(AWK) '$$0 == ".Dd" {$$2 = "$(TZPFMS_DATE)"}  $$1 == ".Dt" { print ".ds doc-volume-operating-system" }  $$0 == ".Os" {$$2 = "tzpfms"; $$3 = "$(TZPFMS_VERSION)"}  {print}' > $@
+	$(AWK) -f pp.awk $< TZPFMS_PASSPHRASE_HELPER_MAN='$(DEF_TPH_MAN)' | $(AWK) '/^$$/ {prev_empty=1; next} $$1 == "#" && $$2 ~ /^[0-9]*$$/ {prev_empty=0; next}  {if(prev_empty) print ""; prev_empty=0; print}' | $(AWK) '$$0 == ".Dd" {$$2 = "$(TZPFMS_DATE)"}  $$1 == ".Dt" { print ".ds doc-volume-operating-system" }  $$0 == ".Os" {$$2 = "tzpfms"; $$3 = "$(TZPFMS_VERSION)"}  {print}' > $@
 	! $(MANDOC) -Tlint $@ 2>&1 | grep -vE -e 'mandoc: outdated mandoc.db' -e 'STYLE: referenced manual not found' -e 'STYLE: operating system explicitly specified: Os tzpfms' -e 'WARNING: cross reference to self: Xr zfs-tpm.*-change-key 8' -e 'STYLE: input text line longer than 80 bytes'
 # The "WARNING: unknown font, skipping request: TS.+fC[RBI]" one: see https://bugs.debian.org/992002
 
@@ -90,7 +98,7 @@ $(OUTDIR)%$(EXE) : $(subst $(SRCDIR),$(OBJDIR),$(subst .cpp,$(OBJ),$(SRCDIR)bin/
 
 $(OBJDIR)%$(OBJ) : $(SRCDIR)%.cpp
 	@mkdir -p $(dir $@)
-	$(CXX) $(CXXAR) $(INCAR) $(VERAR) -c -o$@ $^
+	$(CXX) $(CXXAR) $(INCAR) $(VERAR) $(DEF_TPH) -c -o$@ $^
 
 $(BLDDIR)test/%$(OBJ) : $(TSTDIR)%.cpp
 	@mkdir -p $(dir $@)
diff --git a/README.md b/README.md
index 5a48944..07925a2 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,11 @@ The output binaries are trimmed of extraneous dependencies, so they're all just
 
 `mandoc` is required for HTML manuals. Set `MANDOC=true` to forgo this.
 
+The default `$TZPFMS_PASSPHRASE_HELPER` is the null string.
+To set a different default, set `TZPFMS_PASSPHRASE_HELPER` and `TZPFMS_PASSPHRASE_HELPER_MAN` for `make` — `$`s need to be double-escaped and `'`s need to be full-`'` escaped (i.e. `'\''`).
+
+As an example, for a sensible default value of `exec systemd-ask-password --id="tzpfms:$2" "$1:"` for OOB systemd integration, pass `TZPFMS_PASSPHRASE_HELPER='exec systemd-ask-password --id="tzpfms:$$2" "$$1"'` and `TZPFMS_PASSPHRASE_HELPER_MAN='Ic exec Nm systemd-ask-password Fl -id Ns Li = Ns Qo Li tzpfms:\& Ns Ar $$2 Qc Qo Ar $$1 Ns Li ":\&" Qc'`.
+
 ### Installation
 
 Copy the `out/zfs-tpm*` binaries corresponding to the back-ends you want to `/sbin`,
diff --git a/man/passphrase.h b/man/passphrase.h
index b827163..8e9601a 100644
--- a/man/passphrase.h
+++ b/man/passphrase.h
@@ -29,4 +29,6 @@ If the helper doesn't exist
 .Pq the shell exits with Sy 127 ,
 a diagnostic is issued and the normal prompt is used as fall-back.
 If it fails for any other reason, the prompting is aborted.
+.
+TZPFMS_PASSPHRASE_HELPER_MAN{}
 .El
diff --git a/pp.awk b/pp.awk
index b7d3dbe..6330ebc 100644
--- a/pp.awk
+++ b/pp.awk
@@ -10,6 +10,13 @@ BEGIN {
 	dir = ARGV[1]
 	sub(/[^\/]+$/, "", dir)
 
+	for (i = 2; i < ARGC; ++i) {
+		eq = index(ARGV[i], "=")
+		v = substr(ARGV[i], eq + 1)
+		gsub(/\\n/, "\n", v)
+		macro_contents[substr(ARGV[i], 1, eq - 1)] = v
+	}
+
 	incfile = ""
 }
 
diff --git a/src/fd.cpp b/src/fd.cpp
index f151355..de51700 100644
--- a/src/fd.cpp
+++ b/src/fd.cpp
@@ -218,10 +218,17 @@ static int get_key_material_raw(const char * whom, bool again, bool newkey, uint
 	return 0;
 }
 
+#ifndef TZPFMS_PASSPHRASE_HELPER
+#define TZPFMS_PASSPHRASE_HELPER
+#endif
+#define STRINGIFY_(...) #__VA_ARGS__
+#define STRINGIFY(...) STRINGIFY_(__VA_ARGS__)
+
 static int get_key_material_dispatch(const char * whom, bool again, bool newkey, uint8_t *& buf, size_t & len_out) {
 	static const char * helper{};
+	printf("'%s'\n", STRINGIFY(TZPFMS_PASSPHRASE_HELPER));
 	if(!helper)
-		helper = getenv("TZPFMS_PASSPHRASE_HELPER") ?: "";
+		helper = getenv("TZPFMS_PASSPHRASE_HELPER") ?: STRINGIFY(TZPFMS_PASSPHRASE_HELPER);
 	if(*helper) {
 		if(auto err = get_key_material_helper(helper, whom, again, newkey, buf, len_out); err != -1)
 			return err;