diff --git a/packaging/rules/debian-qt/rules b/packaging/rules/debian-qt/rules
index 9f76fa9ee5a21df8a58cfcf0048cb788a3d439ab..e4a325860ab322b0e745822281cc7a784db9a292 100755
--- a/packaging/rules/debian-qt/rules
+++ b/packaging/rules/debian-qt/rules
@@ -3,23 +3,43 @@
 
 # export DH_VERBOSE = 1
 
-# Number of CPUS
-NO_CPUS=$(shell nproc)
-ifeq ($(NO_CPUS),0)
-NO_CPUS=1
-endif
+# Return the minimum value of two integer arguments.
+min = $(shell echo $$(( $(1) < $(2) ? $(1) : $(2) )))
+max = $(shell echo $$(( $(1) > $(2) ? $(1) : $(2) )))
+
+# Number of CPUs to build Qt.
+NO_CPUS := $(call max,$(shell nproc),1)
+
+# There can be multiple builds of Qt in parallel.  The following
+# should match the maximum number of per-machine workers used in the
+# CI.
+MAX_PARALLEL_BUILDS := 4
+
+# qtwebengine (aka chromium) takes a ton of memory per build process,
+# up to 2.3 GiB.  Cap the number of jobs based on the amount of
+# available memory to try to guard against OOM build failures.
+AVAILABLE_MEMORY := $(shell free -g | grep -E '^Mem:' | awk '{print $$7}')
+MEMORY_REQUIRED_PER_CORE := 2	# in GiB
+COMPUTED_JOB_COUNT := \
+  $(call max,$(shell echo $$(( $(AVAILABLE_MEMORY) \
+                               / $(MEMORY_REQUIRED_PER_CORE) \
+                               / $(MAX_PARALLEL_BUILDS) ))),1)
+JOB_COUNT = $(call min,$(NO_CPUS),$(COMPUTED_JOB_COUNT))
 
 %:
 	dh $@
 
 override_dh_auto_configure:
-	MAKEFLAGS="-j$(NO_CPUS) V=1" \
-		./configure \
-			-opensource \
-			-confirm-license \
-			-nomake examples \
-			-nomake tests \
-			-prefix "${QT_JAMI_PREFIX}"
+	./configure \
+	  -opensource \
+	  -confirm-license \
+	  -nomake examples \
+	  -nomake tests \
+	  -prefix "${QT_JAMI_PREFIX}"
+
+override_dh_auto_build:
+	@echo Building Qt using $(JOB_COUNT) parallel jobs
+	$(MAKE) -j$(JOB_COUNT) V=1 NINJAFLAGS="-j$(JOB_COUNT)"
 
 override_dh_auto_install:
 	dh_auto_install -Smakefile -- INSTALL_ROOT=$(CURDIR)/debian/tmp/
diff --git a/packaging/rules/rpm/jami-libqt.spec b/packaging/rules/rpm/jami-libqt.spec
index f7534b1869c0527081fb90b27cbc6c7f8ae40955..dc7aca83dc182ba3e19f559a52337fef6b2b90fe 100644
--- a/packaging/rules/rpm/jami-libqt.spec
+++ b/packaging/rules/rpm/jami-libqt.spec
@@ -2,6 +2,21 @@
 %define version     RELEASE_VERSION
 %define release     0
 
+# qtwebengine (aka chromium) takes a ton of memory per build process,
+# up to 2.3 GiB.  Cap the number of jobs based on the amount of
+# available memory to try to guard against OOM build failures.
+%define min(a,b) %(echo $(( %1 < %2 ? %1 : %2 )))
+%define max(a,b) %(echo $(( %1 > %2 ? %1 : %2 )))
+
+%define cpu_count %max %(nproc) 1
+%define available_memory %(free -g | grep -E '^Mem:' | awk '{print $7}')
+# Required memory in GiB.
+%define max_parallel_builds 4
+%define memory_required_per_core 2
+%define computed_job_count_ %(echo $(( %available_memory / %memory_required_per_core / %max_parallel_builds )))
+%define computed_job_count %max %computed_job_count_ 1
+%define job_count %min %cpu_count %computed_job_count
+
 Name:          %{name}
 Version:       %{version}
 Release:       %{release}%{?dist}
@@ -31,18 +46,20 @@ This package contains Qt libraries for Jami.
 %setup -n qt-everywhere-src-%{version}
 
 %build
-	./configure \
-		-opensource \
-		-confirm-license \
-		-nomake examples \
-		-nomake tests \
-		-prefix "%{_libdir}/qt-jami"
-	sed -i 's,bin/python,bin/env python3,g' qtbase/mkspecs/features/uikit/devices.py
-	make -j8 V=1
+echo "Building Qt using %{job_count} parallel jobs"
+./configure \
+  -opensource \
+  -confirm-license \
+  -nomake examples \
+  -nomake tests \
+  -prefix "%{_libdir}/qt-jami"
+sed -i 's,bin/python,bin/env python3,g' qtbase/mkspecs/features/uikit/devices.py
+# Chromium is built using Ninja, which doesn't honor MAKEFLAGS.
+make -j%{job_count} V=1 NINJAFLAGS="-j%{job_count}"
 
 %install
-make -j8 INSTALL_ROOT=%{buildroot} V=1 install
+make -j%{job_count} INSTALL_ROOT=%{buildroot} V=1 install
 
 %files
 %defattr(-,root,root,-)
-%{_libdir}/qt-jami
\ No newline at end of file
+%{_libdir}/qt-jami