Couple of things to watch out for, Clojure doesn't pattern match on the args in the way you seem to be expecting, so this will blow the stack (i.e. calling qsort with the empty list won't call the 0-argument method you have there.)
The error you're running into is that pop/peek isn't defined for lazy sequences. doall will force your lazy-sequence, but it's still of type LazySeq:
>(type (lazy-seq [1 2 3]))
clojure.lang.LazySeq
So putting the base-case into an if/else branch, and switching pop/peek for rest/first would look like so:
(defn qsort
([list]
(if (seq list)
(let [piv (first list)
f-half (filter (fn [n] (<= n piv)) (rest list))
s-half (filter (fn [n] (> n piv)) (rest list))]
(concat (qsort f-half) (cons piv (qsort s-half))))