diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c
index 4f6d985ae6..a61b8b22b7 100644
--- a/libavcodec/hevc_refs.c
+++ b/libavcodec/hevc_refs.c
@@ -38,6 +38,8 @@ void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags)
     frame->flags &= ~flags;
     if (!frame->flags) {
         ff_thread_release_buffer(s->avctx, &frame->tf);
+        ff_thread_release_buffer(s->avctx, &frame->tf_grain);
+        frame->needs_fg = 0;
 
         av_buffer_unref(&frame->tab_mvf_buf);
         frame->tab_mvf = NULL;
@@ -208,7 +210,7 @@ int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
         if (nb_output) {
             HEVCFrame *frame = &s->DPB[min_idx];
 
-            ret = av_frame_ref(out, frame->frame);
+            ret = av_frame_ref(out, frame->needs_fg ? frame->frame_grain : frame->frame);
             if (frame->flags & HEVC_FRAME_FLAG_BUMPING)
                 ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_BUMPING);
             else
@@ -216,6 +218,9 @@ int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
             if (ret < 0)
                 return ret;
 
+            if (!(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN))
+                av_frame_remove_side_data(out, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
+
             av_log(s->avctx, AV_LOG_DEBUG,
                    "Output frame with POC %d.\n", frame->poc);
             return 1;
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index 57a61752a3..56811bee12 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -2881,14 +2881,14 @@ static int set_side_data(HEVCContext *s)
         s->sei.timecode.num_clock_ts = 0;
     }
 
-    if (s->sei.film_grain_characteristics.present &&
-        (s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)) {
+    if (s->sei.film_grain_characteristics.present) {
         HEVCSEIFilmGrainCharacteristics *fgc = &s->sei.film_grain_characteristics;
         AVFilmGrainParams *fgp = av_film_grain_params_create_side_data(out);
         if (!fgp)
             return AVERROR(ENOMEM);
 
         fgp->type = AV_FILM_GRAIN_PARAMS_H274;
+        fgp->seed = s->ref->poc; /* no poc_offset in HEVC */
 
         fgp->codec.h274.model_id = fgc->model_id;
         if (fgc->separate_colour_description_present_flag) {
@@ -2983,6 +2983,18 @@ static int hevc_frame_start(HEVCContext *s)
 
     s->ref->frame->key_frame = IS_IRAP(s);
 
+    s->ref->needs_fg = s->sei.film_grain_characteristics.present &&
+        !(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) &&
+        !s->avctx->hwaccel;
+
+    if (s->ref->needs_fg) {
+        s->ref->frame_grain->format = s->ref->frame->format;
+        s->ref->frame_grain->width = s->ref->frame->width;
+        s->ref->frame_grain->height = s->ref->frame->height;
+        if ((ret = ff_thread_get_buffer(s->avctx, &s->ref->tf_grain, 0)) < 0)
+            goto fail;
+    }
+
     ret = set_side_data(s);
     if (ret < 0)
         goto fail;
@@ -3009,6 +3021,31 @@ fail:
     return ret;
 }
 
+static int hevc_frame_end(HEVCContext *s)
+{
+    HEVCFrame *out = s->ref;
+    const AVFrameSideData *sd;
+    int ret;
+
+    if (out->needs_fg) {
+        sd = av_frame_get_side_data(out->frame, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
+        av_assert0(out->frame_grain->buf[0] && sd);
+        ret = ff_h274_apply_film_grain(out->frame_grain, out->frame, &s->h274db,
+                                       (AVFilmGrainParams *) sd->data);
+
+        if (ret < 0) {
+            av_log(s->avctx, AV_LOG_WARNING, "Failed synthesizing film "
+                   "grain, ignoring: %s\n", av_err2str(ret));
+            out->needs_fg = 0;
+        } else {
+            if ((ret = av_frame_copy_props(out->frame_grain, out->frame)) < 0)
+                return ret;
+        }
+    }
+
+    return 0;
+}
+
 static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
 {
     HEVCLocalContext *lc = s->HEVClc;
@@ -3167,6 +3204,9 @@ static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
             else
                 ctb_addr_ts = hls_slice_data(s);
             if (ctb_addr_ts >= (s->ps.sps->ctb_width * s->ps.sps->ctb_height)) {
+                ret = hevc_frame_end(s);
+                if (ret < 0)
+                    goto fail;
                 s->is_decoded = 1;
             }
 
@@ -3426,6 +3466,13 @@ static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, HEVCFrame *src)
     if (ret < 0)
         return ret;
 
+    if (src->needs_fg) {
+        ret = ff_thread_ref_frame(&dst->tf_grain, &src->tf_grain);
+        if (ret < 0)
+            return ret;
+        dst->needs_fg = 1;
+    }
+
     dst->tab_mvf_buf = av_buffer_ref(src->tab_mvf_buf);
     if (!dst->tab_mvf_buf)
         goto fail;
@@ -3478,6 +3525,7 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
     for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
         ff_hevc_unref_frame(s, &s->DPB[i], ~0);
         av_frame_free(&s->DPB[i].frame);
+        av_frame_free(&s->DPB[i].frame_grain);
     }
 
     ff_hevc_ps_uninit(&s->ps);
@@ -3531,6 +3579,11 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
         if (!s->DPB[i].frame)
             goto fail;
         s->DPB[i].tf.f = s->DPB[i].frame;
+
+        s->DPB[i].frame_grain = av_frame_alloc();
+        if (!s->DPB[i].frame_grain)
+            goto fail;
+        s->DPB[i].tf_grain.f = s->DPB[i].frame_grain;
     }
 
     s->max_ra = INT_MAX;
diff --git a/libavcodec/hevcdec.h b/libavcodec/hevcdec.h
index 482638a8e5..8963aa83ae 100644
--- a/libavcodec/hevcdec.h
+++ b/libavcodec/hevcdec.h
@@ -39,6 +39,7 @@
 #include "hevc_ps.h"
 #include "hevc_sei.h"
 #include "hevcdsp.h"
+#include "h274.h"
 #include "internal.h"
 #include "thread.h"
 #include "videodsp.h"
@@ -395,7 +396,10 @@ typedef struct DBParams {
 
 typedef struct HEVCFrame {
     AVFrame *frame;
+    AVFrame *frame_grain;
     ThreadFrame tf;
+    ThreadFrame tf_grain;
+    int needs_fg; /* 1 if grain needs to be applied by the decoder */
     MvField *tab_mvf;
     RefPicList *refPicList;
     RefPicListTab **rpl_tab;
@@ -525,6 +529,7 @@ typedef struct HEVCContext {
     HEVCDSPContext hevcdsp;
     VideoDSPContext vdsp;
     BswapDSPContext bdsp;
+    H274FilmGrainDatabase h274db;
     int8_t *qp_y_tab;
     uint8_t *horizontal_bs;
     uint8_t *vertical_bs;
