diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 2fb62413f..679084bdf 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -1602,8 +1602,9 @@ public final class VideoDetailFragment
 
         binding.detailControlsDownload.setVisibility(
                 StreamTypeUtil.isLiveStream(info.getStreamType()) ? View.GONE : View.VISIBLE);
-        binding.detailControlsBackground.setVisibility(info.getAudioStreams().isEmpty()
-                ? View.GONE : View.VISIBLE);
+        binding.detailControlsBackground.setVisibility(
+                info.getAudioStreams().isEmpty() && info.getVideoStreams().isEmpty()
+                        ? View.GONE : View.VISIBLE);
 
         final boolean noVideoStreams =
                 info.getVideoStreams().isEmpty() && info.getVideoOnlyStreams().isEmpty();
diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java
index 934beba19..e87c93114 100644
--- a/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java
+++ b/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java
@@ -11,7 +11,9 @@ import androidx.annotation.Nullable;
 import com.google.android.exoplayer2.source.MediaSource;
 
 import org.schabi.newpipe.extractor.stream.AudioStream;
+import org.schabi.newpipe.extractor.stream.Stream;
 import org.schabi.newpipe.extractor.stream.StreamInfo;
+import org.schabi.newpipe.extractor.stream.VideoStream;
 import org.schabi.newpipe.player.helper.PlayerDataSource;
 import org.schabi.newpipe.player.mediaitem.MediaItemTag;
 import org.schabi.newpipe.player.mediaitem.StreamInfoTag;
@@ -41,22 +43,50 @@ public class AudioPlaybackResolver implements PlaybackResolver {
             return liveSource;
         }
 
-        final List<AudioStream> audioStreams = getNonTorrentStreams(info.getAudioStreams());
-
-        final int index = ListHelper.getDefaultAudioFormat(context, audioStreams);
-        if (index < 0 || index >= info.getAudioStreams().size()) {
+        final Stream stream = getAudioSource(info);
+        if (stream == null) {
             return null;
         }
 
-        final AudioStream audio = info.getAudioStreams().get(index);
         final MediaItemTag tag = StreamInfoTag.of(info);
 
         try {
             return PlaybackResolver.buildMediaSource(
-                    dataSource, audio, info, PlaybackResolver.cacheKeyOf(info, audio), tag);
+                    dataSource, stream, info, PlaybackResolver.cacheKeyOf(info, stream), tag);
         } catch (final ResolverException e) {
             Log.e(TAG, "Unable to create audio source", e);
             return null;
         }
     }
+
+    /**
+     * Get a stream to be played as audio. If a service has no separate {@link AudioStream}s we
+     * use a video stream as audio source to support audio background playback.
+     *
+     * @param info of the stream
+     * @return the audio source to use or null if none could be found
+     */
+    @Nullable
+    private Stream getAudioSource(@NonNull final StreamInfo info) {
+        final List<AudioStream> audioStreams = getNonTorrentStreams(info.getAudioStreams());
+        if (!audioStreams.isEmpty()) {
+            final int index = ListHelper.getDefaultAudioFormat(context, audioStreams);
+            return getStreamForIndex(index, audioStreams);
+        } else {
+            final List<VideoStream> videoStreams = getNonTorrentStreams(info.getVideoStreams());
+            if (!videoStreams.isEmpty()) {
+                final int index = ListHelper.getDefaultResolutionIndex(context, videoStreams);
+                return getStreamForIndex(index, videoStreams);
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    Stream getStreamForIndex(final int index, @NonNull final List<? extends Stream> streams) {
+        if (index >= 0 && index < streams.size()) {
+            return streams.get(index);
+        }
+        return null;
+    }
 }
diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/PlaybackResolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/PlaybackResolver.java
index ead127250..9c8cbb8f6 100644
--- a/app/src/main/java/org/schabi/newpipe/player/resolver/PlaybackResolver.java
+++ b/app/src/main/java/org/schabi/newpipe/player/resolver/PlaybackResolver.java
@@ -158,6 +158,26 @@ public interface PlaybackResolver extends Resolver<StreamInfo, MediaSource> {
 
         return cacheKey.toString();
     }
+
+    /**
+     * Use common base type {@link Stream} to handle {@link AudioStream} or {@link VideoStream}
+     * transparently. For more info see {@link #cacheKeyOf(StreamInfo, AudioStream)} or
+     * {@link #cacheKeyOf(StreamInfo, VideoStream)}.
+     *
+     * @param info   the {@link StreamInfo stream info}, to distinguish between streams with
+     *               the same features but coming from different stream infos
+     * @param stream the {@link Stream} ({@link AudioStream} or {@link VideoStream})
+     *               for which the cache key should be created
+     * @return a key to be used to store the cache of the provided {@link Stream}
+     */
+    static String cacheKeyOf(final StreamInfo info, final Stream stream) {
+        if (stream instanceof AudioStream) {
+            return cacheKeyOf(info, (AudioStream) stream);
+        } else if (stream instanceof VideoStream) {
+            return cacheKeyOf(info, (VideoStream) stream);
+        }
+        throw new RuntimeException("no audio or video stream. That should never happen");
+    }
     //endregion